2009-04-13 11 views
6

Vedo un sacco di risposte come questa:una domanda sul nidificati collezioni in Django e Query efficienza

Printing a list of persons with more than one home each home with more than one

ho provato quella risposta con modelli simili e sembra che un modo terribilmente inefficiente di fare Questo. Ogni iterazione sembra creare una query separata che a volte genera migliaia di query su un database. Mi rendo conto che è possibile memorizzare nella cache i set di query, ma sembra ancora molto sbagliato. Quindi la domanda è: usi questo metodo? Se no, come lo fai?

risposta

6

Questa è una domanda molto buona e non limitata al framework ORM di Django.

ho sempre la sensazione che sia importante ricordare alcuni dei problemi che un object-relational mapping (ORM) quadro risolve:

  • Object-oriented CRUD: Se il resto della applicazione si basa su forti principi orientati agli oggetti, l'accesso alla persistenza dei dati tramite oggetti rende il codice solo molto più coerente, internamente coerente e talvolta più breve.

  • Incapsulamento a livello di persistenza: Un ORM fornisce un livello chiaro nell'applicazione per l'accesso DB. Incapsula tutte le funzioni necessarie per leggere/scrivere i dati in un punto, l'epitome del cosiddetto principio DRY (non ripetersi). Questo rende alcune cose molto più semplici: modifiche al modello, perché tutto il codice di selezione e inserimento/aggiornamento DB si trova in un punto invece che in tutta l'app, sicurezza, perché tutto l'accesso al DB passa attraverso una posizione e test, perché è facile prendere in giro i modelli di dati e accedere se sono delineati chiaramente.

  • protezione di SQL: Mentre è facile per garantire l'uso di SQL grezzo contro gli attacchi di iniezione e tale, è ancora più facile se si dispone di un quadro ORM come un unico punto di DB-contatto che lo fa per te in modo da non avere pensarci.

Si noti che la velocità non è nell'elenco. Un ORM è un livello di riferimento indiretto tra il tuo codice e il database. Certamente i progettisti di ORM sono responsabili della scrittura di un framework che produca buone istruzioni SQL, ma un ORM è pensato per fornire efficienza a livello di codice e architettura, non di efficienza di esecuzione. Uno sviluppatore che ha letto un libro di base su SQL sarà sempre in grado di ottenere prestazioni migliori parlando direttamente al DB.

Ci sono sicuramente delle strategie per contrastare questo, e in Django quelle sono select_related() come ozan ha menzionato, e sito/vista/cache diversa, ma non ti daranno le stesse prestazioni di un'istruzione SQL diretta. Per questo motivo, non utilizzerei mai un framework ORM che non fornisce alcun meccanismo per l'emissione di un'istruzione SQL raw in quelle occasioni in cui ho bisogno di velocità. Ad esempio, ricorro spesso a SQL raw quando si genera un report di grandi dimensioni estratto dal database che unisce molte tabelle; la modalità ORM può richiedere alcuni minuti, il modo SQL può richiedere alcuni secondi.

Detto ciò, non inizio mai a preoccuparmi di ogni singola query. Il mio consiglio per chiunque si avvicini a un livello ORM è: non fare il baby-sitter al database di ORM. Scrivi la tua applicazione o modulo, quindi esegui il profilo, modificando le aree che necessitano veramente di incremento delle prestazioni o utilizzando la memorizzazione nella cache/select_related per ridurre la chattiness complessiva della tua applicazione.

+0

+1 risposta solida. :) –

+0

Ottima risposta! Dopo aver giocato con select_related, ho deciso di confrontarlo con l'SQL diretto. Sono sicuro che non ti sorprenderà sentire oltre 1.000.000 di richieste, l'SQL diretto è stato 15 volte più veloce. Anche con select related, django vuole ancora parlare molto con il database. – Matt

+0

Hmmm ... interessante! Hai un blog? Dovresti esprimere tutto con attenzione per evitare di essere fiammeggiato, ma la procedura e i risultati del benchmark sarebbero una lettura molto interessante per la comunità. –

4

È possibile utilizzare select_related() queryset method per ridurre il numero di query del database. Puoi anche specificare la profondità, quindi nell'esempio dato se il modello del numero di telefono aveva relazioni estranee aggiuntive, avresti usato select_related (depth = 2) per evitare di selezionare ulteriori "livelli" di entità correlate.

+0

Hmm, immagino che il libro che ho letto non menzioni il fatto che è possibile selezionare specifici modelli correlati. Stavo incontrando un problema in cui l'utilizzo di select_related() avrebbe anche richiamato 4 o 5 altre molte relazioni di cui non avevo bisogno. È tempo di leggere djangoproject.com prima di fare domande! Grazie. – Matt