2010-03-03 5 views
6

Sto provando a creare una sitemap XML usando CakePHP, da una tabella che ha più di 50.000 record al momento, ogni record equivalente a un URI nella sitemap. Ora il problema che sto affrontando è CakePHP mi sta esaurendo la memoria durante la generazione di esso, per due motivi:Suggerimento CakePHP per iterare una tabella enorme e generare una sitemap?

  1. Un find('all') sta costruendo un array associativo enorme del l'intero set di 50.000 URI.
  2. Poiché non voglio emettere HTML dal controller stesso, sto trasferendo l'array associativo contenente URI, priorità, frequenza di modifica ecc. Alla vista con una chiamata $this->set() - che è ancora enorme, contenente 50.000 indici.

È possibile eseguire questa operazione seguendo le linee guida MVC e CakePHP?

risposta

2

Sei sicuro di aver esaurito la memoria su 50.000 record? Anche se una riga ha una dimensione di 1K (abbastanza grande), dovresti trattare con ~ 50 MB di dati? Il mio P1 aveva abbastanza RAM per gestirlo. Imposta memory_limit in php.ini superiore a quello predefinito. (Si consideri anche il tweaking di max_execution_time.)

D'altra parte, se si considera il set di dati troppo grande e lo si elabora con un uso intensivo di risorse, non si deve servire dinamicamente questa pagina, è l'esca DDoS perfetta. (Almeno lo metterei in cache pesantemente.) Puoi programmare un cron job per rigenerare la pagina ogni X ore con uno script lato server libero dalla penalità MVC di servire tutti i dati contemporaneamente alla vista, potrebbe funzionare le file in sequenza.

+0

La mappa del sito funziona perfettamente sulla mia casella di sviluppo locale. Una volta distribuito nel mio hosting condiviso dove ho una memoria molto limitata, esplode. Questo è esattamente ciò a cui stavo pensando, volevo solo ricontrollare e assicurarmi che io vada in quel modo perché non sono rimaste opzioni CakePHP/MVC. Grazie! –

1

Hai provato unBindModel (se si dispone di relazioni) ...

Ogni volta che devo fare enormi query in cakephp mi basta usare i "regolari" mysql-funzioni come mysql_query, mysql_fetch_assoc ecc Molto più veloce, e nessuna mancanza di memoria ...

+0

Questa è una tabella singola SELECT. Sembra che la vecchia scuola MySQL sia l'efficiente e solo la strada da percorrere, ma a quel punto sono fuori da CakePHP. E ho ancora il problema di come rendere l'array associato calcolato. –

3

Ho avuto un problema simile questa settimana e sono incappato nel comportamento Containable. Ciò ti consente di ridurre qualsiasi query relativa alla relazione (se ne hai).

La soluzione migliore sarebbe utilizzare a livello di programmazione LIMIT and OFFSET e passare in rassegna i piccoli pezzi del recordset alla volta. Questo ti evita di riempire i record di 50K in memoria in una sola volta.

+0

Grazie per la risposta. Non ho alcuna tabella correlata e la query è più o meno una semplice operazione 'SELECT'. L'esecuzione di più query è qualcosa che volevo evitare. Inoltre, anche se lo faccio, come trasferisco ancora i dati alla vista? –

+0

Visualizzerai tutti i record 50k nella stessa vista? In caso contrario, la maggior parte dei modelli di impaginazione funziona bene con la query limite/offset. Se devi visualizzarli tutti in una volta, magari scavare nel tuo php.ini (se hai accesso amministratore al tuo server) e cambiare memory_limit ad un valore più alto. Questo potrebbe risolvere i tuoi problemi di memoria con una ricerca ('tutti). Se la tabella contiene molti campi, utilizzare il valore "fields" per restringere il necessario (come indicato in un altro commento). – bojo

2

find ('all') è troppo avido, dovrai essere più specifico se non vuoi esaurire la memoria.

Come indicato sopra, utilizzare il comportamento Contenente. Se avete solo bisogno di risultati dal vostro tavolo, (senza tavoli associati) e solo per un paio di campi, una query più esplicito come questo dovrebbe essere migliore:

$results = $this->YourModel->find('all', array(
    'contain' => false, 
    'fields' => array('YourModel.name', 'YourModel.url') 
); 

si dovrebbe anche prendere in considerazione l'aggiunta di un meccanismo di cache HTML (cakePHP ha un builtin o usa quello suggested by Matt Curry).

Ovviamente sarà una versione memorizzata nella cache e non sarà perfettamente aggiornata alla tua lista. Se si desidera un maggiore controllo, è sempre possibile salvare il risultato nella cache della torta (utilizzando), utilizzando i callback afterSave/afterDelete del modello per aggiornare il valore memorizzato nella cache e ricreare il file xml memorizzato nella cache da qui.

+0

In particolare, guarda l'argomento "fields" per find(). –

4

So che questa domanda è vecchia, ma per query davvero enormi non c'è ancora una soluzione valida, penso.

Per ripetere un enorme set di risultati è possibile utilizzare i metodi di DboSource.

prima ottenere il DBO

$dbo = $this->Model->getDataSource(); 

creare la query

$sql = $dbo->buildStatement($options); 

Quindi eseguire l'istruzione e scorrere i risultati

if ($dbo->execute($sql)) 
{ 
    while ($dbo->hasResult() && $row = $dbo->fetchResult()) { 
     // $row is an array with same structure like find('first') 
    } 
} 
+0

A partire da CakePHP 2.4.4, '$ dbo-> buildStatement' richiede due parametri. Inoltre, '$ dbo-> buildStatement' restituisce solo un SQL non valido senza nome tabella. Dopo aver scavato nella sorgente ho usato '$ this-> generateAssociationQuery ($ model, null, null, null, null, $ queryData, false, $ null)' – VCD

Problemi correlati