Promise Concurrency Queue
Run async operations with a concurrency limit to prevent overwhelming servers and network resources.
Buffer database inserts and flush in batches for dramatically faster data loading.
You are loading thousands of records into a database and individual INSERTs are too slow.
class BatchInserter
{
private array $buffer = [];
private int $batchSize;
private PDO $pdo;
public function __construct(PDO $pdo, int $batchSize = 100)
{
$this->pdo = $pdo;
$this->batchSize = $batchSize;
}
public function add(array $row): void
{
$this->buffer[] = $row;
if (count($this->buffer) >= $this->batchSize) {
$this->flush();
}
}
public function flush(): void
{
if (empty($this->buffer)) {
return;
}
$columns = array_keys($this->buffer[0]);
$placeholders = '(' . implode(',', array_fill(0, count($columns), '?')) . ')\;
$allPlaceholders = implode(',', array_fill(0, count($this->buffer), $placeholders));
$sql = sprintf(
'INSERT INTO records (%s) VALUES %s',
implode(',', $columns),
$allPlaceholders
);
$values = [];
foreach ($this->buffer as $row) {
foreach ($row as $value) {
$values[] = $value;
}
}
$stmt = $this->pdo->prepare($sql);
$stmt->execute($values);
$this->buffer = [];
}
}
Let us trace what happens when you insert 250 records with a batch size of 100:
Record 1-99: Added to buffer → No database call
Record 100: Buffer full → Flush 100 records in ONE INSERT
Record 101-199: Added to buffer → No database call
Record 200: Buffer full → Flush 100 records in ONE INSERT
Record 201-250: Added to buffer → Call flush() manually at end
Final flush: Flush remaining 50 records in ONE INSERT
Total database calls: 3 (instead of 250)
Each database INSERT has overhead: network round-trip, query parsing, transaction handling. Batching reduces this overhead dramatically:
Single inserts: 250 records × 5ms overhead = 1,250ms
Batched inserts: 3 queries × 5ms overhead = 15ms + bulk insert time
Real-world improvement: Often 10-50x faster
$inserter = new BatchInserter($pdo, 100);
foreach ($dataStream as $record) {
$inserter->add([
'name' => $record['name'],
'email' => $record['email'],
'created_at' => date('Y-m-d H:i:s'),
]);
}
// Do not forget the final flush for remaining records
$inserter->flush();
The buffer pattern ensures efficient database operations regardless of how many records you process. Small datasets work fine. Large datasets stay efficient.