Che cosa qualifica "troppe richieste di database" nel codice?

17

Questa è una discussione io e alcuni dei miei colleghi stanno avendo e ho pensato che sarei venuto qui e vedere se ci fosse un consenso generale su di esso.

In pratica si tratta dei seguenti 2 pareri sulle chiamate al database: 1. Effettuare una chiamata di grandi dimensioni per ottenere tutto ciò che potrebbe essere necessario per ridurre il numero di chiamate DB del database 2. Effettua chiamate separate più piccole in base a quanto richiesto per ridurre la dimensione delle chiamate DB

Dove questo sta entrando in gioco specialmente è nel codice comune. Useremo l'esempio di una classe Employee perché è abbastanza semplice.

Diciamo che la tua classe Employee ha 10 attributi di valore (nome, cognome, hiredate, ecc.) e poi 2 attributi di classe ... 1 che punta a una classe Department e quindi 1 supervisor che punta a un altro oggetto Employee .

Nella mentalità n. 1, si effettuerà una chiamata che restituisce i dati Impiegato nonché i campi necessari per popolare gli attributi Reparto e Supervisore ... o almeno i campi utilizzati più spesso da tali oggetti secondari.

Nella mentalità n. 2, si popolerebbe dapprima solo l'oggetto Impiegato e quindi si compila solo gli oggetti Reparto e Supervisore se e quando sono effettivamente richiesti.

La posizione di

2 è piuttosto diretta ... minimizzare la dimensione delle richieste e il numero di oggetti del database che devono essere colpiti ogni volta che viene effettuata una di queste richieste. La posizione numero 1 è che, anche se potesse essere implementata correttamente, il semplice fatto che il codice avrebbe dovuto effettuare più connessioni causerebbe più tensione nella connessione tra il server web e il database invece di ridurlo.

La forza trainante dietro la ricerca di questo è che la quantità di traffico tra il nostro server web e server di database sta diventando fuori controllo.

    
posta user107775 26.09.2011 - 14:39
fonte

8 risposte

8

Se la forza trainante di questa domanda è troppo traffico, hai esaminato la memorizzazione nella cache degli oggetti usati di frequente? Ad esempio: dopo aver ottenuto gli oggetti Dipendente e Reparto e Supervisore, forse sarebbe una buona idea aggiungerli in una cache in modo che se vengono nuovamente richiesti nel prossimo futuro, sono già nella cache e non è necessario recuperarli ancora. Ovviamente, la cache dovrà lasciare scadere gli oggetti usati raramente e dovrà anche essere in grado di rimuovere gli oggetti che sono stati modificati dall'applicazione e salvati nel database.

A seconda del linguaggio e dei framework che stai utilizzando, potrebbe esserci già un framework di memorizzazione nella cache che può fare (o la maggior parte) di ciò che ti serve. Se usi Java, puoi consultare la Apache Commons-Cache (non l'ho usata per un po ', e mentre sembra assopito, è ancora disponibile ed è stato abbastanza buono l'ultima volta che l'ho usato).

    
risposta data 26.09.2011 - 15:50
fonte
3

Verifica sempre la leggibilità e la chiarezza la prima volta che scrivi qualcosa. Puoi quindi refactoring se e quando è necessario. Esegui il test del carico per trovare i colli di bottiglia, in molti casi non è il numero di chiamate che causano il problema ma quelle mal scritte.

Per quanto riguarda ciò che classifica come troppi, ciò dipende dall'applicazione. Per la maggior parte delle applicazioni Web, qualsiasi cosa al di sotto dei 30 secondi è quasi accettabile. Vorrei parlare con i tuoi utenti delle loro aspettative.

    
risposta data 26.09.2011 - 15:49
fonte
3

La tua domanda sembra basata sul presupposto che devi indovinare quali dati saranno necessari per una determinata pagina. Questo non è il caso. Non è semplice come l'approccio ingenuo, ma puoi architettare il tuo codice in modo da sapere se hai bisogno degli attributi di supervisore o di reparto prima di effettuare qualsiasi chiamata al database.

    
risposta data 26.09.2011 - 17:26
fonte
3

Queste sono le regole che uso, forse ti saranno utili.

  1. Misura per primo! Non vedrò nemmeno il codice che "potrebbe essere lento" a meno che non riesca a vedere il traffico che scorre verso quella risorsa e quella risorsa stia rispondendo lentamente.
  2. 1 richiesta = query K. il numero di volte in cui parlo al database è completamente determinato dal tipo di risorsa richiesta; e mai dalla natura della richiesta o stato di quella risorsa; Nel tuo esempio, probabilmente sono al massimo 3 query: 1 per i dipendenti, 1 per i dipartimenti e 1 per i supervisori; Non importa quanti di essi ci siano.
  3. Non eseguire query su ciò che non utilizzerai . Se si tratta di HTTP di cui stiamo parlando, non ha senso interrogare i dati per dopo; non c'è più tardi; ogni richiesta inizia da una lavagna pulita. A volte ho bisogno di la maggior parte delle colonne da una tabella, ma a volte ho solo bisogno di uno o due; quando conosco esattamente i campi di cui ho bisogno, chiederò proprio questo.
  4. Lancia l'hardware al problema. I server sono economici; A volte è possibile ottenere prestazioni sufficienti spostando il database in una casella più potente; o invio di alcune query a una replica di sola lettura.
  5. Prima invalida la cache, quindi implementa la memorizzazione nella cache. L'urgenza di inserire spesso o di difficile interrogare i dati in una cache è strong; ma troppo spesso, trascurare i dati inutilizzati o scadere dei dati sostituiti viene trascurato. Se sai come estrarre i dati dalla cache; quindi sei sicuro mettendolo nella cache; Se risulta più costoso invalidare la cache piuttosto che fare semplicemente la query; quindi non hai bisogno di una cache.
risposta data 26.09.2011 - 19:19
fonte
2

Entrambe le strategie qui sono perfettamente valide. Ci sono vantaggi e svantaggi per ciascuno:

Una chiamata per tutti e 3 gli oggetti:

  • si esibirà più rapidamente
  • ti fornisce esattamente ciò di cui hai bisogno nel caso in cui ne hai bisogno
  • sarà probabilmente utilizzabile solo in un caso (potrebbe comunque essere un caso molto comune)
  • sarà più difficile da mantenere
  • dovrà essere mantenuto più spesso (dato che cambierà se uno qualsiasi degli schemi degli 3 oggetti o dei dati necessari cambiano)

Una chiamata per oggetto (3 chiamate totali)

  • Ti dà una chiamata generica per popolare una singola istanza di ogni tipo di oggetto; possono quindi essere usati indipendentemente
  • Sarà più gestibile in quanto la struttura della query sarà più semplice.
  • Sarà più lento (non necessariamente 3 volte più lento, ma l'overhead è aumentato per gli stessi dati)
  • Può causare problemi con il recupero di dati non necessari (estraendo l'intero record quando hai bisogno di un campo è dispendioso)
  • Può causare problemi N + 1 quando esiste una relazione molti-a-uno, se la query a record singolo viene inviata N volte, una per record nella raccolta.
risposta data 26.09.2011 - 16:22
fonte
1

Per me, troppe richieste DB stanno facendo più richieste del necessario per caricare i dati richiesti in un dato momento.

Quindi non ti servono i dati, non sprecare memoria per evitare un secondo viaggio dopo. Ma se hai bisogno della quantità di dati, devi ridurre al minimo le chiamate al db.

Quindi disponi di entrambe le opzioni e utilizza ognuna di esse dove la situazione lo richiede.

EDIT: tieni presente che questo ofcourse dipende anche dalla tua situazione. Se si tratta di una WebApp, ad esempio, dovresti avere considerazioni diverse rispetto a quando si tratta di un'app desktop che accede al DB all'interno della tua rete, anziché sul Web per WepApp.

    
risposta data 26.09.2011 - 15:51
fonte
1

Connettersi al DB, inviare richieste e farle analizzare in genere richiede tempo significativo rispetto al recupero dei risultati, quindi la tendenza generale è concatenare il maggior numero possibile di query in una richiesta.

Tuttavia, fare tutto questo in un colpo renderà il codice non mantenibile. Invece, di solito viene raggiunto da un ulteriore livello di astrazione: il codice pianifica diverse richieste quando sono necessarie, quindi il motore lo analizza come una grande richiesta (probabilmente usando la cache sulla strada) e quindi le risposte vengono inviate secondo necessità.

Ovviamente non sempre tutti possono essere recuperati in una query: spesso avrai una query che fornisce i dati necessari per costruire la query successiva, quindi dovrai ripetere. Fasci di query ancora sconcertanti e che eseguono il maggior numero possibile in una sola volta è meglio di centinaia di piccoli scatti nel database.

Quindi pianifica ciò di cui hai bisogno, richiedi e recuperalo, se ne è necessario altro, richiedi e recuperalo nuovamente, quindi utilizza i dati nella generazione di contenuti. Sicuramente evitare di utilizzare richieste di database come l'inizializzazione di variabili locali sparse per tutto il codice.

    
risposta data 26.09.2011 - 16:01
fonte
1

Non sappiamo abbastanza della tua applicazione per sapere quale scelta sei colpevole di ottimizzare troppo presto. Con quale frequenza vengono utilizzati i dati del Supervisore? Sembra che potrebbe essere uno spreco, ma non lo sappiamo. Se li tieni separati, potresti essere in grado di monitorare il tuo sistema per vedere quanto spesso finiscono per essere usati insieme. Quindi puoi decidere di combinarli in una sola chiamata. Altrimenti, se inizi a creare un collo di bottiglia con questa grande chiamata, da dove inizi a scovare i problemi? Difficile identificare ciò che ha senso omettere. Altri campi di dati potrebbero essere aggiunti a questo processo.

Sarebbe interessante sapere quanto di questo viene dalla memoria db vs disco. Non c'è niente che mi faccia pensare che il dipartimento abbia più o meno la possibilità di cambiare rispetto all'indirizzo.

    
risposta data 26.09.2011 - 16:21
fonte

Leggi altre domande sui tag