2011-09-28 19 views
8

Sto lavorando a un progetto in cui devo raccogliere molti dati dal database. Sto usando Symfony2 (symfony bf1281aebdc842a39ec0eb7438e1ea3fca9b9705) e Doctrine2 (doctrine 3b3186ee98392802a44118cd421a3530119aa7eaand) come base di lavoro.Come gestire raccolte e associazioni di doctrine di grandi dimensioni

Il problema che incontro è che devo recuperare circa 15.000 articoli. Dopodiché, ho bisogno di scorrere tutti questi dati per ottenere più dati sulla base dell'id dell'articolo (ci sono associazioni dirette e indirette con i media o i prezzi (ereditati), ecc ...). Va bene per circa 50-100 record, ma se voglio usare più record ci vuole un sacco di tempo per recuperare tutto dal database.

C'è un modo per scorrere i dati senza utilizzare tutta la RAM rimanente? C'è un modo per dire alla dottrina di smettere di usare i riferimenti?

Grazie in anticipo per qualsiasi aiuto!

risposta

3

Difficile rispondere senza ulteriori dettagli su ciò che si sta tentando di fare, esattamente.

La dottrina in genere non si adatta bene ai principali scricchiolii di dati come si potrebbe descrivere. Ho diversi progetti che ricorrono all'utilizzo di DBAL per eseguire raw SQL per cose come report complicati.

Detto questo, se in realtà non è necessario caricare tutti i record 15k contemporaneamente, non caricarli contemporaneamente! Prendi 50, processali, libera memoria e ripeti. Questo approccio può mantenere i totali mentre si procede, quindi è possibile ottenere alcune statistiche aggregate per l'intero set.

Detto questo, se hai bisogno di materiale aggregato, stai probabilmente costruendo una sorta di "rapporto", e potresti star meglio usando l'SQL puro, o anche alcune stored procedure, e non lasciare che il L'ORM è coinvolto.

+0

E mi dica, esattamente quello che Applicazione guidata da symfony potresti avere bisogno di 15k record contemporaneamente? Solo il data mining richiede così tanti dati e thath non dovrebbe essere alimentato da Symfony. –

3

Si può considerare di usare iterativa idratazione (step-by-step) in Dottrina:

$em = $this->getDoctrine()->getEntityManager(); 
$q = $em->createQuery("<DQL to select the objects I want>"); 
$iterableResult = $q->iterate(); 
while (($row = $iterableResult->next()) !== false) { 
    // do stuff with the data in the row, $row[0] is always the object 
    $em->detach($row[0]); // detach from Doctrine, so that it can be GC'd immediately 
} 

Dettagli da this article, sotto Messa elaborazione oggetto

+0

FYI: il collegamento è rotto – Tieme

1

V'è in realtà un altro modo, ma si non gli piacerà È possibile utilizzare pure mysql :) Quando ho cercato di ottenere 450k oggetti dal database utilizzando getRepository ("..") -> findAll() - ha richiesto ore fino alla chiusura dello script :). Così ho usato il codice come

$c = $doctrine->getConnection(); 
    mysql_connect($c->getParams()['host'],$c->getParams()['user'],$c->getParams()['password']);//$link = 
    mysql_select_db($c->getParams()['dbname']); 
    $qid = mysql_query("SELECT id FROM TABLENAME"); 
    while($i = mysql_fetch_row($qid)) { 
     $object = $doctrine->getRepository("...")->find($i[0]); 

ho avuto primo oggetto dopo 1,7 secondi, che è assolutamente accettabile per me. Tranne il codice disordinato :(

Dopo googling un po 'mi trova si mette in discussione e doctrine manuall. Dopo aver riscritto ho ottenuto il codice

$iterableResult = $doctrine->getManager()->createQuery("SELECT c FROM ENTITY c")->iterate(); 

    while (($row = $iterableResult->next()) !== false) { 
     $object = $row[0]; 
    } 

codice sopra previsto prima voce 2,4 secondi, che è estremamente veloce, come per le voci Doctrine2 e 450K nella tabella

il mio punto è -. Doctrine2 hanno già quasi tutto il necessario per "vita reale", l'utilizzo, ma è ancora in grado di semplificare la vita con la vecchia scuola di codice brutto :)

AGGIORNAMENTO: non dimenticare di eseguire il distacco a cascata di tutte le entità caricate.E in Symfony2 è inoltre necessario disattivare la registrazione SQL mediante l'esecuzione di codice

$doctrine->getConnection()->getConfiguration()->setSQLLogger(null); 
6

salvare un'altra linea utilizzando:

$iterableResult = $doctrine->getManager()->createQuery("SELECT c FROM ENTITY c")->iterate(); 

while ((list($obj) = $iterableResult->next()) !== false) { 
    // do something with $obj 
    $em->detach($obj); 
} 
0

Da dottrina documentation:

$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; 
} 
$em->flush(); 
Problemi correlati