Résumé
Le problème est que field
est pas un bon candidat pour l'indexation, en raison de la nature de b-trees.
Explication
Supposons que vous avez une table qui a les résultats de 500.000 lancers de pièces, où le tirage au sort est soit 1
(têtes) ou 0
(queues):
CREATE TABLE toss (
id int NOT NULL AUTO_INCREMENT,
result int NOT NULL DEFAULT '0',
PRIMARY KEY (id)
)
select result, count(*) from toss group by result order by result;
+--------+----------+
| result | count(*) |
+--------+----------+
| 0 | 250290 |
| 1 | 249710 |
+--------+----------+
2 rows in set (0.40 sec)
Si vous Vous voulez sélectionner un tirage au sort (au hasard) où le tirage au sort était pile, alors vous devez chercher dans votre table, en choisissant un lieu de départ aléatoire.
select * from toss where result != 1 limit 123456, 1;
+--------+--------+
| id | result |
+--------+--------+
| 246700 | 0 |
+--------+--------+
1 row in set (0.06 sec)
explain select * from toss where result != 1 limit 123456, 1;
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | toss | ALL | NULL | NULL | NULL | NULL | 500000 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
Vous voyez que vous effectuez une recherche séquentielle dans toutes les lignes pour trouver une correspondance.
Si vous créez un index sur le champ toss
, votre index contiendra deux valeurs, chacune contenant environ 250 000 entrées.
create index foo on toss (result);
Query OK, 500000 rows affected (2.48 sec)
Records: 500000 Duplicates: 0 Warnings: 0
select * from toss where result != 1 limit 123456, 1;
+--------+--------+
| id | result |
+--------+--------+
| 246700 | 0 |
+--------+--------+
1 row in set (0.25 sec)
explain select * from toss where result != 1 limit 123456, 1;
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | toss | range | foo | foo | 4 | NULL | 154565 | Using where |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
Maintenant, vous recherchez moins d'enregistrements, mais le temps de recherche a augmenté de 0,06 à 0,25 secondes. Pourquoi? Parce que l'analyse séquentielle d'un index est en fait moins efficace que l'analyse séquentielle d'une table, pour les index avec un grand nombre de lignes pour une clé donnée.
Regardons les indices sur ce tableau:
show index from toss;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| toss | 0 | PRIMARY | 1 | id | A | 500000 | NULL | NULL | | BTREE | |
| toss | 1 | foo | 1 | result | A | 2 | NULL | NULL | | BTREE | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
L'indice primaire est un bon indice: il y a 500.000 lignes, et il y a 500.000 valeurs. Disposé dans un BTREE, vous pouvez rapidement identifier une seule ligne en fonction de l'identifiant.
L'index foo est un mauvais index: il y a 500 000 lignes, mais seulement 2 valeurs possibles. C'est à peu près le pire des cas pour un BTREE - tous les frais généraux de la recherche de l'index, et encore à chercher dans les résultats.
De quel moteur s'agit-il? Montrer la sortie de EXPLAIN – Mchl