web-dev-qa-db-fra.com

Dans MySQL, l'ordre des colonnes dans une clause WHERE affecte-t-il les performances des requêtes?

J'ai des problèmes de performances sur certaines requêtes de base de données qui ont de grands ensembles de résultats possibles.

La requête en question, j'ai trois ANDs dans la clause WHERE

L'ordre des clauses est-il important?

Comme dans, si je mets la clause ASI_EVENT_TIME en premier (car cela supprimerait la plupart des résultats de l'une des clauses.

Cela améliorera-t-il le temps d'exécution de la requête?

REQUETE:

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

EXPLIQUER la requête:

+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
| 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 |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+

En utilisant:

PHP 5.2

MySQL 5.0.51a-3ubuntu5.4

Propel 1.3

Symfony 1.2.5

41
Patrick

Je ne pense pas. L'optimiseur de requêtes doit être suffisamment intelligent.

Vous pouvez essayer de réorganiser les clauses WHERE et voir que EXPLAINS vous dit la même chose dans chaque cas.


À propos de ce qui peut être fait pour optimiser cette requête: existe-t-il un index sur ASI_EVENT_TIME? (C'est le plus crucial, je pense, pour cette requête, car vous triez également les résultats en l'utilisant).

Existe-t-il des index sur les deux autres champs (ASI_SEISMO_ID et ASI_ACTIVITY_ID)?

Il serait utile de publier la structure de la table.

26
ypercubeᵀᴹ

De la documentation :

Si la table a un index à plusieurs colonnes, tout préfixe le plus à gauche de l'index peut être utilisé par l'optimiseur pour rechercher des lignes. Par exemple, si vous avez un index à trois colonnes sur (col1, col2, col3), vous avez des capacités de recherche indexées sur (col1), (col1, col2) et (col1, col2, col3).

MySQL ne peut pas utiliser un index si les colonnes ne forment pas un préfixe le plus à gauche de l'index.

Alors oui, cela devrait être le même que l'ordre des colonnes dans un indice composé .

15
Gaius

Non, ça n'a pas d'importance.

L'optimiseur effectue un tas de transformations simples juste après avoir analysé le SQL - c'est l'une d'entre elles.

10
Morgan Tocker

O f foo ET bar

optimise la même chose que

O bar bar et foo

Cependant,

OERE non égal # 1 ET non égal # 2

Impossible d'optimiser les deux parties. Par exemple,

O a ENTRE 1 et 3 ET b> 17

ne peut pas faire bon usage de INDEX (a, b) ou INDEX (b, a)

Pour le formuler différemment, tous les tests '=' ET ensemble dans la clause WHERE sont utilisés en premier, puis un non - '=' (IN, ENTRE,>, etc.) peut être manipulé. Un seul peut être efficacement optimisé.

Votre requête contient 3 clauses de ce type.

En fin de compte, INDEX (EVENT_TIME) est probablement le plus utile - il vous aidera avec l'un des AND, et il pourrait être utilisé pour éviter le "tri de fichiers" pour ORDER BY.

S'il n'y a pas de lignes en double (pourquoi diable y en aurait-il?), Alors débarrassez-vous de DISTINCT. Cela provoque encore plus d'efforts.

Veuillez indiquer SHOW CREATE TABLE et SHOW TABLE STATUS lorsque vous posez des questions sur les performances.

pdate ... Les versions plus récentes (par exemple, MySQL 5.7) peuvent, dans certaines situations, traiter IN( list of constants ) presque comme =. Pour jouer en toute sécurité, respectez cette commande (chaque partie étant facultative):

  1. N'importe quel nombre de =.
  2. Certains INs.
  3. Au plus une plage.
8
Rick James

MySQL où optimisation doc dit:

Vous pourriez être tenté de réécrire vos requêtes pour accélérer les opérations arithmétiques, tout en sacrifiant la lisibilité. Parce que MySQL effectue automatiquement des optimisations similaires , vous pouvez souvent éviter ce travail et laisser la requête sous une forme plus compréhensible et maintenable. Certaines des optimisations effectuées par MySQL sont les suivantes:

  • ...

  • Pour chaque table dans une jointure, un WHERE plus simple est construit pour obtenir une évaluation WHERE rapide pour la table et aussi pour ignorer les lignes dès que possible .

  • Chaque index de table est interrogé, et le meilleur index est utilisé sauf si l'optimiseur estime que il est plus efficace à utiliser un scan de table . À un moment donné, une analyse a été utilisée selon que le meilleur index s'étendait sur plus de 30% de la table, mais un pourcentage fixe ne détermine plus le choix entre l'utilisation d'un index ou d'une analyse. L'optimiseur est désormais plus complexe et base son estimation sur des facteurs supplémentaires tels que la taille de la table, le nombre de lignes et la taille des blocs d'E/S.

De cette façon, il est rationnel pour l'optimiseur de requête d'omettre l'ordre dans lequel nous avons utilisé les colonnes de la requête (non seulement MySQL mais SQL est un langage déclaratif et doit faire ce que nous voulons pas comme nous le voulons).

Cependant, j'aime toujours avoir le même type pour les colonnes d'une clé composite dans la requête, mais c'est parfois inévitable par exemple lorsque nous utilisons ORM ou ActiveRecord, dans certains cadres tels que yii2, la personnalisation des critères de relation sera ajoutée à la fin de une condition "on" mais nous avons toujours besoin des capacités de QueryBuilders dans différentes parties d'une application.

1
Alix