Dans MySQL, l’ordre des colonnes dans une clause WHERE affecte-t-il les performances de la requête?

38

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

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

L'ordre des articles est-il important?

Comme dans, si je mets la clause ASI_EVENT_TIME en premier (car cela enlèverait la plupart des résultats de toutes les clauses.

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

QUESTION:

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

EXPLAIN de 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

Patrick
la source
La commande par est probablement ce qui prend si longtemps. "Utiliser le port de fichiers" peut être extrêmement lent. J'ai trouvé beaucoup plus rapide de commander dans la logique d'application que d'utiliser ORDER BY.
Maclema
J'ai posé cette même question il y a quelque temps (avant ce site) sur stackoverflow. Vérifiez les liens pour les réponses que j'ai reçues là-bas. stackoverflow.com/questions/3805863/…
Scott
2
@maclema - À moins que votre application ne s'exécute sur une machine beaucoup plus rapide que votre base de données, votre assertion est certainement fausse, sans parler de la charge inutile de toute cette logique de tri dans votre application. order byappartient à la base de données.
Jack Douglas

Réponses:

24

Je ne pense pas. L'optimiseur de requête devrait être assez intelligent.

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


A 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 à l’aide de cette requête).

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.

ypercubeᵀᴹ
la source
Je n'ai jamais pensé créer un index des temps d'événement. Je vais essayer cela demain sur une base de données dev et voir s'il y a une différence notable.
Patrick
@Patrick En supposant que toutes les autres requêtes utilisant cet index classent cette date par ordre décroissant, vous souhaitez également commander la clé d'index (activity_seismo_info.ASI_EVENT_TIME) également dans un ordre décroissant.
Matt M
@ MattM Je ne savais pas que vous pourriez commander une clé d'index. Génial Si je commande la clé d'index, cela affectera-t-il nécessairement l'ordre des performances dans la direction opposée au point qu'il est pire que l'absence de clé d'index?
Patrick
@ Patrick Vous avez raison. Mon cerveau est bloqué dans SQL Server. Vous pouvez spécifier un ordre de tri dans MYSQL et il sera analysé, mais il est ignoré. Tous les index sont triés par ordre croissant dans MYSQL. Désolé pour la confusion.
Matt M
13

De la documentation :

Si la table a un index à plusieurs colonnes, l'optimiseur peut utiliser le préfixe le plus à gauche de l'index pour rechercher des lignes. Par exemple, si vous avez un index à trois colonnes sur (col1, col2, col3), vous disposez de fonctionnalités de recherche indexée sur (col1), (col1, col2) et (col1, col2, col3).

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

Alors oui, il devrait être identique à l'ordre des colonnes dans un index composé .

Gaius
la source
4
Si la table a un index à plusieurs colonnes, la sélection des colonnes à gauche est importante, mais l'ordre dans lequel vous sélectionnez n'a pas d'importance. Donc, si vous avez les index a, b, c, et vous l’aurez WHERE c = 'foo' AND a = 'bar' AND b = 'foobar', l’indice est toujours utilisable.
texelate
10

Non, ce n'est pas grave.

L’optimiseur effectue une série de transformations simples immédiatement après l’analyse du code SQL - c’est l’une d’elles.

Morgan Tocker
la source
8

Où foo et bar

optimise le même que

Où bar et foo

cependant,

WHERE non-égal n ° 1 ET non-égal n ° 2

Impossible d'optimiser les deux parties. Par exemple,

OU A 1 ENTRE 3 ET 3 ET b> 17

ne peut pas utiliser correctement INDEX (a, b) ou INDEX (b, a)

Pour le formuler différemment, tous les tests '=' ET combinés dans la clause WHERE sont utilisés en premier, puis un non - '=' (IN, BETWEEN,>, etc.) peut être traité. Pas plus d'un ne peut être efficacement optimisé.

Votre requête a 3 telles clauses.

En fait, INDEX (EVENT_TIME) est probablement le plus utile - il aidera avec l’un des AND, et pourrait être utilisé pour éviter le "fichier" pour ORDER BY.

S'il n'y a pas de lignes en double (pourquoi diable y aurait-il?), Supprimez DISTINCT. Cela provoque encore plus d'effort.

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

Mettre à jour ... Les versions les plus récentes (par exemple, MySQL 5.7) peuvent, dans certaines situations, traiter IN( list of constants )presque de la même manière =. Pour jouer en toute sécurité, respectez cet ordre (chaque partie étant optionnelle):

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

MySQL où le document d'optimisation dit:

Vous pourriez être tenté de réécrire vos requêtes pour accélérer les opérations arithmétiques tout en réduisant la lisibilité. Étant donné 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 facile à gérer. Certaines des optimisations effectuées par MySQL suivent:

  • ...

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

  • Chaque index de table est interrogé, et le meilleur index est utilisé à moins que l'optimiseur ne pense qu'il est plus efficace d'utiliser une analyse de table . À un moment donné, une analyse était utilisée selon que le meilleur index couvrait plus de 30% de la table, mais un pourcentage fixe ne déterminait plus le choix entre utiliser un index ou 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 de bloc d'E / S.

De cette façon, il est rationnel que l'optimiseur de requête omette l'ordre HOW. 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 et non ce que nous voulons).

Cependant, j'aime toujours avoir le même type pour les colonnes d'une clé composite dans la requête, mais cela est parfois inévitable, par exemple lorsque nous utilisons ORM ou ActiveRecord, dans certains frameworks 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.

Alix
la source
-2

TOUT champ utilisé dans vos clauses WHERE / HAVING et ayant une sélectivité élevée (nombre de valeurs uniques / nombre total d'enregistrements> 10% à 20%) DOIT être indexé.

Donc, si votre ASI_EVENT_TIME colonne a plusieurs valeurs possibles, commencez par les indexer. Puis, comme @ypercube l'a dit, essayez de les réorganiser et voyez ce que EXPLAIN vous dit. Devrait être tout autour de la même chose.

De plus, vous souhaitez jeter un coup d'œil à l' indexation des filtres SQL LIKE . Bien que ce ne soit pas ce pour quoi vous avez besoin d’une réponse, vous apprendrez tout de même comment fonctionne l’indexation sous le capot.

* Modifier: reportez - vous aux liens fournis ci-dessous dans les commentaires pour en savoir plus sur l'indexation.

Œil
la source
8
-1 L'indexation de chaque colonne n'est pas une pratique recommandée. Chaque indice vous coûte de multiples façons. Assurez-vous de choisir de bons index, généralement composés de plusieurs colonnes, généralement dans l’ordre de sélectivité et de fréquence utilisés. Cela peut être une inclinaison de SQL Server, mais les informations d'index sont toujours valides: sqlskills.com/BLOGS/KIMBERLY/post/… .
Eric Humphrey - lotsahelp
@Eric Humphrey +1 Pour l'explication et le lien vers le site de Kimberly.
Matt M
vous vous trompez, avoir un index sur une colonne nuit parfois à vos performances sur certaines requêtes: mysqlperformanceblog.com/2007/08/28/… . Vous ne devez JAMAIS utiliser la règle générale: parfois cela fonctionne, parfois pas.
sumar
D'accord, je suis d'accord. Cependant, ceci est valable si la sélectivité de la valeur est faible. Compte tenu du type de données utilisé par Patrick (auteur de la question), à savoir DATETIME, l'indexation est recommandée. Habituellement, ce type de champ a un ensemble de valeurs assez important, sauf en cas de situation inhabituelle où il n’utilise que plusieurs dates possibles. * Je vais modifier ma réponse ci-dessus pour faire une déclaration plus claire et valide.
Eye