Table des matières
http://docs.doctrine-project.org/projects/doctrine-orm/en/2.1/reference/batch-processing.html
Ce chapitre vous montre comment accomplir vrac insertions, mises à jour et supprime avec la Doctrine de manière efficace. Le principal problème avec les opérations en bloc ne sont généralement pas à court de mémoire et cela est surtout ce que les stratégies présentées ici fournissent aide.
Un outil ORM n'est pas principalement bien adapté pour les insertions de masse, mises à jour ou suppressions. Chaque SGBDR a sa propre façon ces opérations et si les options décrites ci-dessous ne sont pas suffisantes pour vos besoins, nous vous recommandons d'utiliser les outils pour votre SGBDR particulier pour ces opérations en masse.
Les inserts en masse dans Doctrine sont mieux réalisées dans des lots, en tirant parti du comportement de l'écriture transactionnelle d'un EntityManager. Le code suivant montre un exemple d'insertion de 10 000 objets d'une taille de 20 par lot. Vous pouvez avoir besoin d'expérimenter avec la taille du lot à trouver la taille qui vous convient le mieux. Agrandir la taille des lots signifie réutilisation déclaration plus préparés à l'interne, mais aussi signifier plus de travail durant le flush.
<?php $batchSize = 20; for ($i = 1; $i <= 10000; ++$i) { $user = new CmsUser; $user->setStatus('user'); $user->setUsername('user' . $i); $user->setName('Mr.Smith-' . $i); $em->persist($user); if (($i % $batchSize) == 0) { $em->flush(); $em->clear(); // Detaches all objects from Doctrine! } }
Il y a 2 possibilités pour les mises à jour de masse avec Doctrine.
La façon de loin la plus efficace pour les mises à jour de masse est d'utiliser une requête UPDATE DQL. Exemple:
<?php $q = $em->createQuery('update MyProject\Model\Manager m set m.salary = m.salary * 0.9'); $numUpdated = $q->execute();
Une solution alternative pour les mises à jour de masse est d'utiliser Query#iterate() qui facilite les itérerations étape par étape des résultats de requête par étape au lieu de charger le résultat entier en mémoire à la fois. L'exemple suivant montre comment faire cela, en combinant l'itération avec la stratégie de batch qui a été déjà utilisé pour les inserts de masse:
<?php $batchSize = 20; $i = 0; $q = $em->createQuery('select u from MyProject\Model\User u'); $iterableResult = $q->iterate(); foreach($iterableResult AS $row) { $user = $row[0]; $user->increaseCredit(); $user->calculateNewBonuses(); if (($i % $batchSize) == 0) { $em->flush(); // Executes all updates. $em->clear(); // Detaches all objects from Doctrine! } ++$i; }
Les itérations ne sont pas possible avec les jointures. La nature de ces jeux de résultats SQL n'est pas adapté pour une hydratation incrémentale.
Il ya deux possibilités pour les suppressions en masse avec Doctrine. Vous pouvez soit lancer une requête simple DQL DELETE ou vous pouvez parcourir les résultats et les enlever un à un.
La façon de loin la plus efficace pour les suppressions de masse est d'utiliser une requête DQL DELETE.
<?php $q = $em->createQuery('delete from MyProject\Model\Manager m where m.salary > 100000'); $numDeleted = $q->execute();
Une solution alternative pour les suppressions de masse est d'utiliser la Query#iterate() qui facilite les itérerations étape par étape des résultats de requête par étape au lieu de charger le résultat entier en mémoire à la fois. L'exemple suivant montre comment faire cela:
<?php $batchSize = 20; $i = 0; $q = $em->createQuery('select u from MyProject\Model\User u'); $iterableResult = $q->iterate(); while (($row = $iterableResult->next()) !== false) { $em->remove($row[0]); if (($i % $batchSize) == 0) { $em->flush(); // Executes all deletions. $em->clear(); // Detaches all objects from Doctrine! } ++$i; }
Les itérations ne sont pas possible avec les jointures. La nature de ces jeux de résultats SQL n'est pas adapté pour une hydratation incrémentale.
Vous pouvez utiliser la méthode iterate() juste pour itérer sur un résultat important et aucune intention de UPDATE ou DELETE. L'instance IterableResult retour de $query->iterate() implémente l'interface Iterator de sorte que vous pouvez traiter un grand résultat, sans problèmes de mémoire en utilisant l'approche suivante:
<?php $q = $this->_em->createQuery('select u from MyProject\Model\User u'); $iterableResult = $q->iterate(); foreach ($iterableResult AS $row) { // do stuff with the data in the row, $row[0] is always the object // detach from Doctrine, so that it can be Garbage-Collected immediately $this->_em->detach($row[0]); }
Les itérations ne sont pas possible avec les jointures. La nature de ces jeux de résultats SQL n'est pas adapté pour une hydratation incrémentale.