Esiste una differenza di esecuzione tra una condizione JOIN e una condizione WHERE?


17

C'è una differenza di prestazioni tra queste due query di esempio?

Query 1:

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y'

Query 2;

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
   and b.tag = 'Y'

Si noti che l'unica differenza è il posizionamento della condizione supplementare; il primo utilizza una WHEREclausola e il secondo aggiunge la condizione alla ONclausola.

Quando eseguo queste query sul mio sistema Teradata, i piani di spiegazione sono identici e il passaggio JOIN mostra la condizione aggiuntiva in ciascun caso. Tuttavia, su questa domanda SO riguardante MySQL, una delle risposte ha suggerito che il secondo stile è preferito perché l' WHEREelaborazione avviene dopo che i join sono stati fatti.

Esiste una regola generale da seguire quando si codificano query come questa? Immagino che debba dipendere dalla piattaforma dal momento che ovviamente non fa alcuna differenza sul mio database, ma forse questa è solo una caratteristica di Teradata. E se è dipendente dalla piattaforma, mi piacerebbe moltissimo per ottenere alcuni riferimenti di documentazione; Davvero non so cosa cercare.


9
Dipende dalla piattaforma, in quanto dipende da come l'ottimizzatore RDBMSes gestisce l'analisi e l'ottimizzazione.
Philᵀᴹ

8
E quella risposta nella domanda collegata merita diversi downvotes. Anche l'ottimizzatore primitivo di MySQL capirà che queste semplici query sono equivalenti e che "la clausola WHERE viene valutata dopo che tutti i join sono stati fatti" è vera solo a livello logico, non nell'esecuzione effettiva.
ypercubeᵀᴹ

1
Non proprio un duplicato; quella domanda e le risposte stavano confrontando la sintassi JOIN "implicita" con "esplicita". Chiedo in particolare le condizioni di partecipazione supplementari.
BellevueBob l'

Non oserò pubblicare una risposta come ho provato prima e ho ottenuto molti voti negativi. Quando ci sono molti join, ho riscontrato casi di innalzamento della condizione nel join con conseguente miglior piano di query (filtrato in anticipo). Sempre gli stessi risultati.
paparazzo,

Risposte:


14

Secondo il capitolo 9 (Parser e Optimizer), Pagina 172 del libro Comprensione di MySQL Internals di Sasha Pachev

Comprensione di MySQL Internals

ecco la suddivisione della valutazione di una query come le seguenti attività:

  • Determinare quali chiavi possono essere utilizzate per recuperare i record dalle tabelle e scegliere quella migliore per ciascuna tabella.
  • Per ogni tabella, decidere se la scansione di una tabella è migliore della lettura su un tasto. Se ci sono molti record che corrispondono al valore della chiave, i vantaggi della chiave vengono ridotti e la scansione della tabella diventa più veloce.
  • Determinare l'ordine in cui le tabelle devono essere unite quando nella query è presente più di una tabella.
  • Riscrivi le clausole WHERE per eliminare il codice morto, riducendo i calcoli non necessari e modificando i vincoli, ove possibile, per aprire la strada all'uso delle chiavi.
  • Elimina le tabelle non utilizzate dal join.
  • Determinare se i tasti possono essere utilizzati per ORDER BYe GROUP BY.
  • Tentare di semplificare le sottoquery e determinare fino a che punto è possibile memorizzare nella cache i loro risultati.
  • Unisci viste (espandi il riferimento della vista come macro)

Sulla stessa pagina, dice quanto segue:

Nella terminologia dell'ottimizzatore MySQL, ogni query è un insieme di join. Il termine join viene utilizzato qui in modo più ampio rispetto ai comandi SQL. Una query su una sola tabella è un join degenerato. Mentre normalmente non pensiamo di leggere i record da una tabella come un join, le stesse strutture e gli algoritmi utilizzati con i join convenzionali funzionano perfettamente per risolvere la query con una sola tabella.

EPILOGO

A causa delle chiavi presenti, della quantità di dati e dell'espressione della query, MySQL Joins può talvolta fare cose per il nostro bene (o per tornare da noi) e trovare risultati che non ci aspettavamo e che non possiamo spiegare rapidamente.

Ho scritto su questa stranezza prima

perché lo Strumento per ottimizzare le query di MySQL potrebbe eliminare alcune chiavi durante la valutazione della query.

Il commento di @ Phil mi aiuta a vedere come pubblicare questa risposta (+1 per il commento di @ Phil)

Il commento di @ ypercube (+1 anche per questo) è una versione compatta del mio post perché l'ottimizzatore di query di MySQL è primitivo. Sfortunatamente, deve essere perché si occupa di motori di archiviazione esterni.

CONCLUSIONE

Per quanto riguarda la tua vera domanda, MySQL Query Optimizer determinerebbe le metriche delle prestazioni di ogni query al termine

  • contando le righe
  • selezione dei tasti
  • massaggiare serie di risultati intermittenti
  • Oh sì, sto facendo il vero JOIN

Probabilmente dovresti forzare l'ordine di esecuzione riscrivendo (refactoring) la query

Ecco la prima query che hai dato

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y';

Prova a riscriverlo per valutare prima WHERE

select count(*)
from   table1 a
join   (select key_col from table2 where tag='Y') b
on     b.key_col=a.key_col;

Ciò altererebbe sicuramente il piano EXPLAIN. Potrebbe produrre risultati migliori o peggiori.

Una volta ho risposto a una domanda in StackOverflow in cui ho applicato questa tecnica. EXPLAIN è stato orrendo, ma le prestazioni sono state dinamite. Funzionava solo perché erano presenti gli indici corretti e l'uso di LIMIT in una sottoquery .

Come per i prezzi delle azioni, quando si tratta di query e si tenta di esprimerle, si applicano restrizioni, i risultati possono variare e le performance passate non sono indicative di risultati futuri.


2
+1 per le informazioni dettagliate specifiche su MySQL e soprattutto per avermi indotto a imparare la differenza tra "Epilogo" e "Conclusione"!
BellevueBob,

Nel mio post, l'epilogo è una sub-conclusione.
RolandoMySQLDBA

6
@Rolando: è possibile aggiungere un Aftermath sui miglioramenti degli ottimizzatori nelle ultime versioni di MariaDB (5.3 e 5.5) e nella versione MySQL (5.6) principale rilasciata di recente. Il che potrebbe rendere inutili alcune riscritture.
ypercubeᵀᴹ

1

Per Oracle, poiché mySQL ha una lunga descrizione, abbiamo 2 modi di alto livello per sfruttare l'ottimizzatore.

Il primo è l'ottimizzazione basata su regole (o RBO). Oracle ha 15 regole set-in-stone che ogni query analizzata tenta di seguire in un ordine prestabilito. Se non è in grado di generare una query ottimizzata dalla regola 1, passerà alla regola 2 e in avanti fino a quando non raggiunge la regola 15.

per maggiori informazioni: https://docs.oracle.com/cd/B10500_01/server.920/a96533/rbo.htm

Questi riguardano i kernel Oracle RDBMS dalla 11.1 in poi che non sono stati convertiti in Cost Based Optimizer (aka CBO). Oracle 11.2 e versioni successive richiedono l'ottimizzatore CBO, ma può forzare l'ottimizzazione di ID SQL specifici nel vecchio metodo RBO se l'utente lo desidera.

Il CBO per Oracle 11.1+ elabora invece diversi piani di esecuzione per lo stesso ID SQL ed esegue quello con il minor costo complessivo previsto. Sfrutta gran parte della logica di RBO, ma analizza le statistiche delle tabelle per creare costi del piano di esecuzione dinamico per ogni operazione che il DB deve fare per fornire all'utente finale i propri dati. L'esecuzione di scansioni di tabelle complete su tabelle molto grandi è molto costosa; l'esecuzione di scansioni di tabelle complete su una tabella con 10 righe è economica. In RBO queste erano considerate operazioni uguali.

per maggiori informazioni: https://oracle-base.com/articles/misc/cost-based-optimizer-and-database-statistics

Per il tuo esempio di query specifica: Oracle probabilmente analizzerebbe le informazioni per fare piani di esecuzione diversi e quindi uno sarà tecnicamente migliore dell'altro. Tuttavia, questa può essere una differenza minima. Osservandolo, sia Oracle RBO che CBO vorrebbero interrogare 1 in più perché si sta eseguendo su un join a meno condizioni e quindi filtrando una colonna specifica dalla tabella temporanea che ha creato dal join.


1

Se hai due query e ritieni che siano equivalenti, può succedere quanto segue:

  1. Entrambe le query hanno lo stesso piano di esecuzione. Va bene ed è quello che ci aspettiamo. Speriamo che sia il piano di esecuzione ottimale per la query.
  2. ci sono diversi piani di esecuzione. Abbiamo due sottotitoli qui.

    2.1 Le query hanno piani di esecuzione diversi ma entrambi i piani funzionano altrettanto bene. Anche questo va bene. Non è necessario che per query equivalenti sia necessario generare lo stesso piano. Ma le prestazioni dovrebbero essere uguali. E ancora speriamo che sia il migliore possibile.

    2.2 Le query hanno piani di esecuzione diversi e un piano è migliore dell'altro. Ancora una volta abbiamo sottocasi:

    2.2.1 I piani sono diversi perché le query non sono equivalenti. Quindi controlla attentamente se sono davvero equivalenti. Nel tuo caso sono davvero equivalenti.

    2.2.2 I piani sono diversi ma le query sono equivalenti. Ciò significa che l'ottimizzatore non è abbastanza maturo. In un mondo perfetto con ottimizzatori perfetti ciò non dovrebbe accadere. Quindi sì, dipende dalla piattaforma e devi studiare documenti specifici della piattaforma per scoprire perché ciò accada.

    2.2.3 I piani sono diversi, le query sono equivalenti, il software del database ha un bug.

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.