Cosa è più veloce, una grande query o molte piccole query?


68

Ho lavorato per diverse aziende e ho notato che alcuni di loro preferiscono avere punti di vista che si uniranno a un tavolo con tutti i suoi "parenti". Ma poi sull'applicazione alcune volte, abbiamo solo bisogno di usare solo 1 colonna.

Quindi sarebbe più veloce fare semplici selezioni e poi "unirle" sul codice di sistema?

Il sistema potrebbe essere php, java, asp, qualsiasi lingua connessa al database.

Quindi la domanda è: cosa sta andando più veloce da un lato server (php, java, asp, ruby, python ...) al database eseguendo una query che ottiene tutto ciò di cui abbiamo bisogno o passando dal lato server al database ed esegue un query che ottiene solo le colonne da una tabella alla volta?


2
Quale implementazione di 'SQL' stai usando? MySQL, Microsoft SQL Server, Oracle, Postgresql, ecc.? Si prega di aggiornare il tag.
RLF,

1
Mysql e Postgresql
sudo.ie,

6
La mia esperienza è che a MySQL non piacciono le query complicate e di solito è più veloce con query molto semplici (ma di più). Query Optimizer di Postgres è molto meglio e lì di solito è più efficiente eseguire una singola query di grandi dimensioni.
a_horse_with_no_name,

3
@a_horse_with_no_name Questa è una generalizzazione molto ampia, specialmente nel contesto di questa domanda. L'ottimizzatore MySQL è davvero molto semplice in base alla progettazione e può causare problemi con join e sottoquery - specialmente su versioni precedenti di MySQL - che altrimenti producono piani più veloci in PostgreSQL, mentre MySQL può essere molto veloce per carichi OLTP puri. Tuttavia, nel contesto della domanda, una singola query di grandi dimensioni sarà più veloce di quella, diciamo, nel peggiore dei casi, un SELECT all'interno di un ciclo di programmazione (indipendentemente dall'RDBMS utilizzato).
jynus,

2
@jynus: beh, la domanda è molto ampia (in più: ho detto "nella mia esperienza" - altre persone potrebbero avere esperienze diverse). Una query all'interno di un LOOP non è mai una buona idea e quasi sempre il risultato di una cattiva progettazione o della mancanza di comprensione su come lavorare con un database relazionale.
a_horse_with_no_name,

Risposte:


69

Ciò che risponderebbe alla tua domanda è l'argomento DECISPOSIZIONE ISCRIVITI.

Secondo la pagina 209 del libro

MySQL ad alte prestazioni

È possibile decomporre un join eseguendo più query a tabella singola invece di un join a più livelli, quindi eseguendo il join nell'applicazione. Ad esempio, invece di questa singola query:

SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id = tag.id
JOIN post ON tag_post.post_id = post.id
WHERE tag.tag = 'mysql';

È possibile eseguire queste query:

SELECT * FROM tag WHERE tag = 'mysql';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN (123,456,567,9098,8904);

Perché mai dovresti farlo? A prima vista sembra dispendioso, perché hai aumentato il numero di query senza ottenere nulla in cambio. Tuttavia, tale ristrutturazione può effettivamente offrire significativi vantaggi in termini di prestazioni:

  • La memorizzazione nella cache può essere più efficiente. Molte applicazioni memorizzano nella cache "oggetti" che si associano direttamente alle tabelle. In questo esempio, se l'oggetto con il tag mysqlè già memorizzato nella cache, l'applicazione salterà la prima query. Se trovi dei messaggi con un ID di 123, 567 o 908 nella cache, puoi rimuoverli IN()dall'elenco. Anche la cache delle query potrebbe trarre vantaggio da questa strategia. Se solo una delle tabelle cambia frequentemente, la decomposizione di un join può ridurre il numero di invalidazioni della cache.
  • L'esecuzione delle query singolarmente può talvolta ridurre la contesa tra i blocchi
  • Fare join nell'applicazione semplifica il ridimensionamento del database posizionando le tabelle su server diversi.
  • Le query stesse possono essere più efficienti. In questo esempio, l'utilizzo di un IN()elenco anziché di un join consente a MySQL di ordinare gli ID di riga e di recuperare le righe in modo più ottimale di quanto sarebbe possibile con un join.
  • È possibile ridurre gli accessi alle righe ridondanti. Fare un join nell'applicazione significa recuperare ogni riga una sola volta., Mentre un join nella query è essenzialmente una denormalizzazione che potrebbe accedere ripetutamente agli stessi dati. Per lo stesso motivo, tale ristrutturazione potrebbe anche ridurre il traffico di rete totale e l'utilizzo della memoria.
  • In una certa misura, è possibile visualizzare questa tecnica come l'implementazione manuale di un join hash invece dell'algoritmo di cicli nidificati che MySQL utilizza per eseguire un join. Un hash join potrebbe essere più efficiente.

Di conseguenza, i join di azioni nell'applicazione possono essere più efficienti quando si memorizzano nella cache e si riutilizzano molti dati da query precedenti, si distribuiscono i dati su più server, si sostituiscono i join con IN()elenchi o un join fa riferimento alla stessa tabella più volte.

OSSERVAZIONE

Mi piace il primo punto elenco perché InnoDB è un po 'pesante quando controlla la cache delle query.

Per quanto riguarda l'ultimo punto elenco, ho scritto un post sull'11 marzo 2013 ( Esiste una differenza di esecuzione tra una condizione JOIN e una condizione WHERE? ) Che descrive l'algoritmo del ciclo nidificato. Dopo averlo letto, vedrai quanto può essere buona la decomposizione del join.

Come per tutti gli altri punti del libro , gli sviluppatori cercano davvero prestazioni come la linea di fondo. Alcuni si basano su mezzi esterni (al di fuori dell'applicazione) per migliorare le prestazioni come l'utilizzo di un disco veloce, ottenere più CPU / core, ottimizzare il motore di archiviazione e ottimizzare il file di configurazione. Altri si piegheranno e scriveranno codice migliore. Alcuni possono ricorrere alla codifica di tutta la business intelligence nelle Stored procedure ma non applicano ancora la scomposizione dei join (vedere Quali sono gli argomenti a favore o per mettere la logica dell'applicazione nel livello del database? Insieme agli altri post). Dipende tutto dalla cultura e dalla tolleranza di ogni negozio di sviluppatori.

Alcuni potrebbero essere soddisfatti delle prestazioni e non toccare più il codice. Altri semplicemente non si rendono conto che ci sono grandi benefici che si possono ottenere se provano a unirsi alla composizione.

Per quegli sviluppatori che sono disposti ...

PROVACI !!!


3
Per quanto riguarda quel link sul passaggio a 3 domande ... Conosco e rispetto Barone, Vadim e Peter, ma non sono d'accordo con questo suggerimento fuorviante. La maggior parte degli argomenti a favore della scissione sono così rari da non essere degni di nota. Attenersi a una singola query con JOINs, quindi cerchiamo di migliorarlo.
Rick James,

2
@RickJames Sono d'accordo con lo spirito del tuo commento. Nel corso degli anni ho visto lavorare in decomposizione per alcuni e fallire per altri. Anche con il set di competenze SQL appropriato, potrebbe funzionare contro di te se la decomposizione del join non viene eseguita correttamente. Nel mio attuale datore di lavoro, molti dipartimenti amano scalare e ridimensionare, specialmente quando è coinvolto un codice legacy e sono disponibili tasche profonde. Con coloro che hanno un gusto di caviale ma budget per le insalate di uova, unire la decomposizione potrebbe valere il rischio ma deve essere fatto nel modo giusto.
RolandoMySQLDBA,

Mi piacerebbe vedere come funziona in un ambiente Oracle se avessi i diritti e il tempo.
Rick Henderson,

Un altro modo in cui può essere più veloce è che se stai facendo un ordine, saranno complessivamente meno i calcoli per ordinare elenchi più piccoli che per ordinare un elenco di grandi dimensioni.
Evan Siroky,

24

In Postgres (e probabilmente qualsiasi RDBMS in misura simile, MySQL in misura minore), meno query sono quasi sempre molto più veloci.

Il sovraccarico di analisi e pianificazione di più query è già più di ogni possibile guadagno nella maggior parte dei casi.

Per non parlare del lavoro aggiuntivo da fare nel client, combinando i risultati, che in genere è molto più lento. Un RDBMS è specializzato in quel tipo di attività e le operazioni si basano su tipi di dati originali. Nessun casting da texte verso risultati intermedi o trasformazione in tipi nativi del client, il che potrebbe persino portare a risultati meno corretti (o errati!). Pensa ai numeri in virgola mobile ...

Inoltre, trasferisci più dati tra il server DB e il client. Questo può essere trascurabile per una mano piena di valori o fare una differenza enorme.

Se più query significano più round trip sul server di database, si raccolgono anche più volte la latenza di rete e l'overhead della transazione, possibilmente anche l'overhead della connessione. Grande, grande perdita.

A seconda della configurazione, la latenza di rete da sola potrebbe richiedere più tempo di tutto il resto per ordini di grandezza.

Domanda correlata su SO:

Potrebbe esserci un punto di svolta per query molto grandi e di lunga durata poiché le transazioni raccolgono blocchi sulle file DB lungo la strada. Le query molto grandi possono contenere molti blocchi per un lungo periodo di tempo che può causare attrito con le query simultanee .


Solo per curiosità, cosa consideri molto grande ?
Sablefoste,

@Sablefoste: dipende molto dai tuoi schemi di accesso. Un punto critico è il momento in cui le transazioni simultanee iniziano a fare la fila, in attesa che vengano rilasciati blocchi o se si accumulano blocchi sufficienti per consumare una parte sostanziale delle risorse. O se le tue domande durano abbastanza a lungo da interferire con il vuoto automatico ...
Erwin Brandstetter,

Ma se prendiamo una situazione piuttosto tipica - una query che utilizza un join esterno e restituisce molti dati ridondanti per la tabella "padre", che deve quindi essere analizzata e ordinata dall'app (molto probabilmente, una libreria ORM) rispetto a un piccola selezione che recupera prima tutti gli ID richiesti e poi un'altra selezione più piccola con IN () invece del join esterno? Il secondo approccio non sarà più efficiente (considerando sia la CPU consumata dal database che l'app e la larghezza di banda delle comunicazioni)?
JustAMartin,

1
@JustAMartin: Sembra il tipo di query che è quasi certamente più veloce quando viene gestita dal pianificatore di query di RDBMS, presupponendo che le query siano corrette. Per quanto riguarda returns lots of redundant data for "parent" table: Perché dovresti restituire dati ridondanti? Restituisci solo i dati che ti servono.
Erwin Brandstetter,

1
Con join esterno RDBMS restituisce i dati dalla tabella padre duplicati per ogni figlio unito, il che significa un sovraccarico di rete e memoria, e quindi qualche ulteriore analisi nello strumento ORM per eliminare i valori padre duplicati e mantenere solo un genitore con n figli. Quindi, con una singola query risparmiamo sul lavoro efficiente del pianificatore di query RDBMS, meno richieste di rete (o pipe locali) ma perdiamo su ulteriori payload non necessari e spostando i dati nella libreria ORM. Immagino sia come sempre: misurare prima di ottimizzare.
JustAMartin,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.