Skip to content

Commit 8f07ca8

Browse files
committed
patch: optimisation de l'insertion de gros volume de données
utilisation de array_chunk pour limiter le lot de données à insérer utilisation de bulkInsert à la place de insert avec de garantir une insertation rapide
1 parent 364afb9 commit 8f07ca8

1 file changed

Lines changed: 85 additions & 38 deletions

File tree

src/Seeder/Seed.php

Lines changed: 85 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
*/
2323
class Seed
2424
{
25+
/**
26+
* Taille des lots pour bulk insert
27+
*/
28+
protected const DEFAULT_BULK_SIZE = 100;
29+
2530
/**
2631
* Builder pour la table
2732
*/
@@ -51,6 +56,11 @@ class Seed
5156
*/
5257
protected int $rowCount = 30;
5358

59+
/**
60+
* Taille des lots pour bulk insert
61+
*/
62+
protected int $bulkSize = self::DEFAULT_BULK_SIZE;
63+
5464
/**
5565
* Faut-il vider la table avant ?
5666
*/
@@ -129,6 +139,16 @@ public function rows(int $count): self
129139
return $this;
130140
}
131141

142+
/**
143+
* Définit la taille des lots pour bulk insert
144+
*/
145+
public function bulkSize(int $size): self
146+
{
147+
$this->bulkSize = max(1, $size);
148+
149+
return $this;
150+
}
151+
132152
/**
133153
* Définit des données brutes
134154
*/
@@ -161,6 +181,8 @@ public function truncate(bool $truncate = true): self
161181

162182
/**
163183
* Ajoute un callback avant chaque insertion
184+
*
185+
* @param Closure(array $data, int $index, ?int $insertId): array|null|void $callback
164186
*/
165187
public function beforeInsert(callable $callback): self
166188
{
@@ -171,6 +193,8 @@ public function beforeInsert(callable $callback): self
171193

172194
/**
173195
* Ajoute un callback après chaque insertion
196+
*
197+
* @param Closure(array $data, int $index, ?int $insertId): array|null|void $callback
174198
*/
175199
public function afterInsert(callable $callback): self
176200
{
@@ -188,10 +212,10 @@ public function execute(): void
188212
$this->builder->truncate();
189213
}
190214

191-
if (!empty($this->rawData)) {
215+
if ($this->rawData !== []) {
192216
$this->insertRawData();
193217
} else {
194-
$this->generateData();
218+
$this->generateAndInsertData();
195219
}
196220
}
197221

@@ -202,50 +226,73 @@ protected function insertRawData(): void
202226
{
203227
$columns = array_keys(reset($this->rawData));
204228

205-
foreach ($this->rawData as $index => $row) {
229+
$chunks = array_chunk($this->rawData, $this->bulkSize);
230+
231+
foreach ($chunks as $chunkIndex => $chunk) {
206232
$data = [];
207-
foreach ($columns as $column) {
208-
$data[$column] = $row[$column] ?? null;
233+
foreach ($chunk as $rowIndex => $row) {
234+
$preparedRow = [];
235+
foreach ($columns as $column) {
236+
$preparedRow[$column] = $row[$column] ?? null;
237+
}
238+
239+
$this->executeCallbacks($this->beforeInsertCallbacks, $preparedRow, $rowIndex);
240+
$data[] = $preparedRow;
241+
}
242+
243+
$this->builder->bulkInsert($data);
244+
245+
// Callbacks after (avec l'ID du premier élément comme approximation)
246+
$firstId = $this->db->lastId();
247+
foreach ($data as $index => $row) {
248+
$this->executeCallbacks($this->afterInsertCallbacks, $row, $index, $firstId + $index);
209249
}
210-
211-
$this->executeCallbacks($this->beforeInsertCallbacks, $data, $index);
212-
$this->builder->insert($data);
213-
$this->executeCallbacks($this->afterInsertCallbacks, $data, $index, $this->db->lastId());
214250
}
215251
}
216252

217253
/**
218-
* Génère les données
254+
* Génère et insère les données
219255
*/
220-
protected function generateData(): void
256+
protected function generateAndInsertData(): void
221257
{
222-
// Résoudre les dépendances une seule fois
223-
$dependencies = $this->resolveDependencies();
224-
225-
// Générer les données ligne par ligne
226-
for ($i = 0; $i < $this->rowCount; $i++) {
227-
$row = [];
228-
229-
// Traiter les configurations d'abord (plus rapides)
230-
foreach ($this->columns as $column => $definition) {
231-
$row[$column] = $this->resolveConfig($definition, $dependencies);
232-
}
233-
234-
// Traiter les closures ensuite (plus flexibles)
235-
foreach ($this->closures as $column => $closure) {
236-
$row[$column] = $closure($this->faker, $dependencies, $i);
237-
}
238-
239-
$this->generated[] = $row;
240-
}
241-
242-
// Insérer les données
243-
foreach ($this->generated as $index => $row) {
244-
$this->executeCallbacks($this->beforeInsertCallbacks, $row, $index);
245-
$this->builder->insert($row);
246-
$this->executeCallbacks($this->afterInsertCallbacks, $row, $index, $this->db->lastId());
247-
}
248-
}
258+
// Résoudre les dépendances une seule fois
259+
$dependencies = $this->resolveDependencies();
260+
261+
// Générer les données par lots
262+
$batches = (int) ceil($this->rowCount / $this->bulkSize);
263+
264+
for ($batch = 0; $batch < $batches; $batch++) {
265+
$batchData = [];
266+
$start = $batch * $this->bulkSize;
267+
$end = min($start + $this->bulkSize, $this->rowCount);
268+
269+
for ($i = $start; $i < $end; $i++) {
270+
$row = [];
271+
272+
// Traiter les configurations d'abord (plus rapides)
273+
foreach ($this->columns as $column => $definition) {
274+
$row[$column] = $this->resolveConfig($definition, $dependencies);
275+
}
276+
277+
// Traiter les closures ensuite (plus flexibles)
278+
foreach ($this->closures as $column => $closure) {
279+
$row[$column] = $closure($this->faker, $dependencies, $i);
280+
}
281+
282+
$this->executeCallbacks($this->beforeInsertCallbacks, $row, $i);
283+
284+
$batchData[] = $row;
285+
}
286+
287+
$this->builder->bulkInsert($batchData);
288+
289+
// Callbacks after (avec approximation des IDs)
290+
$firstId = $this->db->lastId();
291+
foreach ($batchData as $offset => $row) {
292+
$this->executeCallbacks($this->afterInsertCallbacks, $row, $start + $offset, $firstId + $offset);
293+
}
294+
}
295+
}
249296

250297
/**
251298
* Résout une configuration

0 commit comments

Comments
 (0)