In MySQL, l'ordine delle colonne in una clausola WHERE influisce sulle prestazioni della query?


38

Sto riscontrando problemi di prestazioni su determinate query del database che hanno grandi possibili set di risultati.

La query in questione, ho tre ANDs nella clausola WHERE

L'ordine delle clausole è importante?

Come in, se inserissi prima la clausola ASI_EVENT_TIME (poiché ciò eliminerebbe la maggior parte dei risultati da una qualsiasi delle clausole.

Ciò migliorerà il tempo di esecuzione della query?

DOMANDA:

SELECT DISTINCT  activity_seismo_info.* 
FROM `activity_seismo_info` 
WHERE 
    activity_seismo_info.ASI_ACTIVITY_ID IS NOT NULL  AND 
    activity_seismo_info.ASI_SEISMO_ID IN (43,44,...,259) AND 
    (
        activity_seismo_info.ASI_EVENT_TIME>='2011-03-10 00:00:00' AND 
        activity_seismo_info.ASI_EVENT_TIME<='2011-03-17 23:59:59'
    ) 

ORDER BY activity_seismo_info.ASI_EVENT_TIME DESC

SPIEGAZIONE della query:

+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
| id | select_type | table   | type  | possible_keys             | key          | key_len | ref  | rows  | Extra                       |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
|  1 | SIMPLE      | act...o | range | act...o_FI_1,act...o_FI_2 | act...o_FI_1 | 5       | NULL | 65412 | Using where; Using filesort |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+

usando:

PHP 5.2

MySQL 5.0.51a-3ubuntu5.4

Propel 1.3

Symfony 1.2.5


L'ORDINE BY probabilmente sta richiedendo così tanto tempo. "Utilizzo di filesort" può essere estremamente lento. Ho trovato l'ordinamento nella logica dell'applicazione MOLTO più veloce rispetto all'utilizzo di ORDER BY.
maclema,

Ho fatto la stessa domanda qualche tempo fa (prima di questo sito) su StackOverflow. Controlla i collegamenti per le risposte che ho ricevuto lì. stackoverflow.com/questions/3805863/…
Scott

2
@maclema - A meno che la tua applicazione non sia in esecuzione su una macchina molto più veloce del tuo database, la tua affermazione è sicuramente falsa, per non parlare del carico inutile di tutta quella logica di ordinamento nella tua applicazione. order byappartiene al database.
Jack Douglas,

Risposte:


24

Non la penso così. Query Optimizer dovrebbe essere abbastanza intelligente.

Puoi provare a riorganizzare le clausole WHERE e vedere che EXPLAINS ti dice lo stesso in ogni caso.


Informazioni su cosa si può fare per ottimizzare questa query: esiste un indice su ASI_EVENT_TIME? (questa è la cosa più cruciale che penso per questa query in quanto si ordinano anche i risultati utilizzandola).

Ci sono indici sugli altri due campi (ASI_SEISMO_ID e ASI_ACTIVITY_ID)?

Sarebbe utile se hai pubblicato la struttura della tabella.


Non ho mai pensato di creare un indice dei tempi degli eventi. Lo proverò domani su un dev db e vedrò se c'è qualche differenza evidente.
Patrick,

@Patrick Supponendo che tutte le altre query che utilizzerebbero questo indice stiano ordinando questa data in ordine decrescente, si desidera ordinare la chiave dell'indice (activity_seismo_info.ASI_EVENT_TIME) anche in ordine decrescente.
Matt M

@MattM Non sapevo che POTREBBE ordinare una chiave di indice. Fantastico Se ordino la chiave di indice, ciò danneggerebbe necessariamente l'ordinamento delle prestazioni nella direzione opposta al punto che è peggio di nessuna chiave di indice?
Patrick,

@Patrick Hai ragione. Il mio cervello è bloccato nella terra di SQL Server. È possibile specificare l'ordinamento in MYSQL e verrà analizzato, ma viene ignorato. Tutti gli indici sono ordinati in ordine crescente in MYSQL. Dispiace per la confusione.
Matt M

13

Dalla documentazione :

Se la tabella ha un indice a più colonne, l'ottimizzatore può utilizzare qualsiasi prefisso più a sinistra dell'indice per trovare le righe. Ad esempio, se hai un indice a tre colonne su (col1, col2, col3), hai capacità di ricerca indicizzata su (col1), (col1, col2) e (col1, col2, col3).

MySQL non può utilizzare un indice se le colonne non formano un prefisso più a sinistra dell'indice.

Quindi sì, dovrebbe essere uguale all'ordine delle colonne in un indice composto .


4
Se la tabella ha un indice a più colonne che seleziona le colonne dalla sinistra è importante, ma l'ordine in cui selezioni non ha importanza. Quindi se hai l'indice a, b, c e lo fai WHERE c = 'foo' AND a = 'bar' AND b = 'foobar'e l'indice è ancora idoneo all'uso.
texelate

10

No, non importa.

L'ottimizzatore esegue una serie di semplici trasformazioni subito dopo aver analizzato l'SQL: questa è una di queste.


8

DOVE foo E bar

ottimizza lo stesso di

DOVE bar E foo

Tuttavia,

DOVE non uguale # 1 E non uguale # 2

Impossibile ottimizzare entrambe le parti. Per esempio,

DOVE a TRA 1 e 3 E b> 17

non può fare buon uso di INDICE (a, b) o INDICE (b, a)

Per esprimerlo diversamente, tutti i test '=' AND messi insieme nella clausola WHERE vengono utilizzati per primi, quindi è possibile gestire uno non - '=' (IN, TRA,>, ecc.). Non più di uno può essere efficacemente ottimizzato.

La tua query ha 3 di tali clausole.

A quanto pare, INDEX (EVENT_TIME) è probabilmente il più utile - aiuterà con uno degli AND, e potrebbe essere usato per evitare "filesort" per ORDER BY.

Se non ci sono righe duplicate (perché diavolo ci sarebbe?), Quindi sbarazzarsi di DISTINCT. Ciò provoca uno sforzo ancora maggiore.

Fornire SHOW CREATE TABLE e SHOW TABLE STATUS quando si pongono domande sulla performance.

Aggiornamento ... Le versioni più recenti (ad esempio, MySQL 5.7) possono, in alcune situazioni, trattare IN( list of constants )quasi come =. Per giocare in sicurezza, segui questo ordine (ogni parte è facoltativa):

  1. Qualsiasi numero di =.
  2. Alcuni INs.
  3. Al massimo un intervallo.

1

MySQL dove dice il documento di ottimizzazione :

Potresti essere tentato di riscrivere le tue domande per velocizzare le operazioni aritmetiche, sacrificando la leggibilità. Poiché MySQL esegue automaticamente ottimizzazioni simili , è spesso possibile evitare questo lavoro e lasciare la query in una forma più comprensibile e gestibile. Di seguito alcune delle ottimizzazioni eseguite da MySQL:

  • ...

  • Per ogni tabella in un join, viene costruito un WHERE più semplice per ottenere una rapida valutazione WHERE per la tabella e anche per saltare le righe il prima possibile .

  • Viene interrogato ogni indice di tabella e viene utilizzato l'indice migliore a meno che l'ottimizzatore non ritenga che sia più efficiente utilizzare una scansione di tabella . Una volta, è stata utilizzata una scansione in base al fatto che l'indice migliore si estendesse oltre il 30% della tabella, ma una percentuale fissa non determina più la scelta tra l'utilizzo di un indice o una scansione. L'ottimizzatore ora è più complesso e basa la sua stima su fattori aggiuntivi come la dimensione della tabella, il numero di righe e la dimensione del blocco I / O.

In questo modo è razionale per Query Optimizer omettere l'ordine HOW abbiamo usato le colonne nella query (non solo MySQL ma SQL è un linguaggio dichiarativo e deve fare ciò che vogliamo e non ciò che vogliamo).

Tuttavia, mi piace ancora avere lo stesso tipo per le colonne di una chiave composita nella query, ma a volte è inevitabile, ad esempio, quando utilizziamo ORM o ActiveRecord, in alcuni framework come yii2, la personalizzazione dei criteri di relazione verrà aggiunta alla fine di una condizione "on", ma abbiamo ancora bisogno delle capacità di QueryBuilders in diverse parti di un'applicazione.


-2

QUALSIASI campo utilizzato nelle clausole WHERE / HAVING e ha un'elevata selettività (il numero di valori univoci / il numero totale di record> 10% ~ 20%) DEVE essere indicizzato.

Quindi, se la tua ASI_EVENT_TIMEcolonna ha molti valori possibili, prima indicizzali tutti. Quindi, come ha detto @ypercube, prova a riordinarli e vedi cosa ti dice EXPLAIN. Dovrebbe essere tutto uguale.

Inoltre, vuoi dare un'occhiata all'indicizzazione di filtri LIKE SQL . Sebbene non sia ciò a cui hai bisogno di una risposta, imparerai comunque come funziona l'indicizzazione.

* Modifica: fare riferimento ai collegamenti forniti di seguito nei commenti per ulteriori informazioni sull'indicizzazione.


8
-1 L'indicizzazione di ogni colonna NON è una procedura consigliata. Ogni indice ti costa in diversi modi. Assicurati di scegliere buoni indici, che di solito saranno composti da più colonne, in genere nell'ordine di selettività e frequenza utilizzate. Potrebbe essere inclinato SQL Server, ma le informazioni sull'indice sono ancora valide: sqlskills.com/BLOGS/KIMBERLY/post/… .
Eric Humphrey - lotsahelp,

@Eric Humphrey +1 Per la spiegazione e il link al sito di Kimberly.
Matt M

ti sbagli, avere indice sulla colonna a volte pregiudica la tua performance su query selezionate: mysqlperformanceblog.com/2007/08/28/… . Non dovresti MAI usare la regola empirica: a volte funziona, a volte no.
sumar,

Giusto, sono d'accordo. Tuttavia, questo è valido nel caso in cui la selettività del valore sia bassa. Considerando il tipo di dati utilizzato da Patrick (questo autore di domande), che è DATETIME, si consiglia l'indicizzazione. Di solito questo tipo di campo ha un set di valori abbastanza grande, a meno che non ci sia una situazione strana quando usa solo diverse date possibili. * Modificherò la mia risposta sopra per rendere più chiara e valida la dichiarazione.
Occhio
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.