2010-04-15 15 views
3

Je suis en train de résoudre un problème de performance de requête. Voici un plan de requête prévu d'expliquer:Pourquoi MySQL avec InnoDB effectue-t-il une analyse de table lorsque la clé existe et choisit d'examiner 70 fois plus de lignes?

mysql> explain select * from table1 where tdcol between '2010-04-13 00:00' and '2010-04-14 03:16'; 
+----+-------------+--------------------+-------+---------------+--------------+---------+------+---------+-------------+ 
| id | select_type | table    | type | possible_keys | key   | key_len | ref | rows | Extra  | 
+----+-------------+--------------------+-------+---------------+--------------+---------+------+---------+-------------+ 
| 1 | SIMPLE  | table1    | range | tdcol   | tdcol  | 8  | NULL | 5437848 | Using where | 
+----+-------------+--------------------+-------+---------------+--------------+---------+------+---------+-------------+ 
1 row in set (0.00 sec) 

Cela est logique, puisque l'indice tdcol nommé (KEY tdcol (tdcol)) est utilisé, et environ 5 millions de lignes doit être sélectionné dans cette requête.

Cependant, si je fais une recherche juste une minute de données, nous obtenons ce plan de requête:

mysql> explain select * from table1 where tdcol between '2010-04-13 00:00' and '2010-04-14 03:17'; 
+----+-------------+--------------------+------+---------------+------+---------+------+-----------+-------------+ 
| id | select_type | table    | type | possible_keys | key | key_len | ref | rows  | Extra  | 
+----+-------------+--------------------+------+---------------+------+---------+------+-----------+-------------+ 
| 1 | SIMPLE  | table1    | ALL | tdcol   | NULL | NULL | NULL | 381601300 | Using where | 
+----+-------------+--------------------+------+---------------+------+---------+------+-----------+-------------+ 
1 row in set (0.00 sec) 

L'optimiseur estime que l'analyse sera mieux, mais il est plus 70x plus de lignes à examiner, afin J'ai du mal à croire que le scan de la table est meilleur. En outre, la syntaxe 'USE KEY tdcol' ne modifie pas le plan de requête.

Merci d'avance pour toute aide, et je suis plus qu'heureux de fournir plus d'info/répondre aux questions.

+1

Le caractère deux-points supplémentaire dans la première date de la première requête est-il un mauvais copier/coller? –

+0

devrait être simple sur la clé de date – DRapp

+0

oui great_llama, qui était mauvaise copier-coller. édité. – andysk

Répondre

3

5 millions de sondes d'index pourraient bien être plus chères (beaucoup de lectures de disques aléatoires, synchronisation potentiellement plus compliquée) que de lire toutes les 350 millions de lignes (lectures de disque séquentielles).

Ce cas peut constituer une exception car il est probable que l'ordre des horodatages correspond à peu près à l'ordre des insertions dans la table. Mais, à moins que l'index sur tdcol soit un index "en cluster" (ce qui signifie que la base de données garantit que l'ordre dans la table sous-jacente correspond à l'ordre dans tdcol), il est peu probable que l'optimiseur le sache. En l'absence de cette information de corrélation d'ordre, il serait juste de supposer que les 5 millions de lignes que vous voulez sont réparties à peu près uniformément parmi les 350 millions de lignes, et donc que l'approche d'index impliquera la lecture de la plupart ou presque les pages de la ligne sous-jacente de toute façon (dans ce cas, le balayage sera beaucoup moins cher que l'approche de l'index, moins de lectures purement et simplement et séquentiellement au lieu de lectures aléatoires).

+0

Merci Doug. Vos hypothèses sont vraies - cette colonne datetime 'tdcol' n'est pas dans un index clusterisé, simplement un index simple - parce que, malheureusement, la valeur n'est pas unique, nous avons plusieurs enregistrements par seconde. Et oui, l'ordre de l'index correspond étroitement à l'ordre des insertions/mise en page des données sur le disque, mais l'optimiseur n'a aucun moyen de le savoir. Et vous faites un point intéressant en termes de pages - si les lignes indexées sont distribuées aléatoirement et qu'il y a au moins 70 lignes par page, cela seul justifierait l'analyse. – andysk

+0

MySQL nécessite que les index clusterisés soient uniques? Pourquoi? –

+0

C'est ainsi que je lis ceci: http://dev.mysql.com/doc/refman/5.1/en/innodb-index-types.html Je ne vois pas pourquoi un index cluster devrait être unique. – andysk

0

Le générateur de requêtes de MySQL a une limite lors de la détermination de l'utilisation d'un index. Comme vous l'avez correctement identifié, MySQL a décidé qu'un scan de table serait plus rapide que l'utilisation de l'index, et ne sera pas dissuadé de prendre cette décision. L'ironie est que lorsque la gamme de clés correspond à plus d'un tiers de la table, c'est probablement juste. Alors pourquoi dans ce cas?

Je n'ai pas de réponse, mais j'ai des doutes sur le fait que MySQL n'a pas assez de mémoire pour explorer l'index. Je regarderais les paramètres de mémoire du serveur, en particulier le pool de mémoire Innodb et certains des autres pools de stockage de clés.

+0

Merci statiquesan. Ce que vous dites a du sens, et en fait cette boîte a un manque de mémoire par rapport à la taille de la table. Fait intéressant, cependant, j'ai reconfiguré le pool de mémoire tampon jusqu'à 27 Go de mémoire à partir de 5,5 Go de mémoire sans autres changements et il n'a pas du tout changé les plans de requête. – andysk

0

Quelle est la répartition de vos données? Essayez d'exécuter min(), avg(), max() pour voir où c'est. Il est possible que cette minute fasse la différence dans la quantité d'informations contenues dans cette plage.

Il peut aussi être juste le réglage de base de InnoDB Il ya quelques facteurs comme la taille de la page, et la mémoire comme la statique dit. Vous pouvez définir explicitement un index B + Tree.

+0

Il s'agit d'un champ datetime que j'essaie de sélectionner sur une période de plus d'un an. La moyenne des derniers jours est d'environ 5M. C'est assez bien réparti. Dans ce cas, cette minute est de 1200 enregistrements, ce qui n'est pas significatif. Je suis d'accord sur le fait que mes paramètres sont importants - mes paramètres se conforment à peu près à cela (http://www.mysqlperformanceblog.com/2007/11/01/innodb-performance-optimization-basics/), mais je devrai vérifier la taille de la page et définissant explicitement un index B + Tree. – andysk

0

"donc j'ai du mal à croire que la numérisation de la table est meilleure."

True. VOUS avez avoir du mal à le croire. Mais l'optimiseur semble ne pas le faire.Je ne vais pas me prononcer sur votre «droit» par rapport à votre optimiseur étant «juste». Mais les optimiseurs agissent comme ils le font et, dans l'ensemble, leur capacité «intellectuelle» doit encore être considérée comme assez limitée. Cela dit, vos statistiques de base de données affichent-elles une valeur MAX (pour cette colonne) égale à la valeur «une seconde de plus»? Si oui, alors l'optimiseur pourrait avoir conclu que toutes les lignes satisfont de toute façon la limite supérieure, et pourraient avoir décidé de procéder différemment, comparé au cas où il doit conclure que, "oh, il y a certainement quelques lignes qui ont gagné ne satisfaisons pas non plus la limite supérieure, donc je vais utiliser l'index juste pour être du bon côté ".

+0

Merci pour les commentaires Erwin - Comment est-ce que je regarderais le MAX dans les statistiques puisqu'il n'est pas dans l'état de table? – andysk