Essayons d'abord FORCE INDEX
pour choisir soit ef
ou fe
. Les délais sont trop courts pour obtenir une image claire de ce qui est plus rapide, mais `EXPLAIN montre une différence :
Forcer la plage sur filetime
première. (Remarque :la commande dans WHERE
n'a aucun impact.)
mysql> EXPLAIN SELECT COUNT(*), AVG(fsize)
FROM files FORCE INDEX(fe)
WHERE ext = 'gif' AND filetime >= '2015-01-01'
AND filetime < '2015-01-01' + INTERVAL 1 MONTH;
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
| 1 | SIMPLE | files | range | fe | fe | 14 | NULL | 16684 | Using index condition |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
Forcer la faible cardinalité ext
d'abord :
mysql> EXPLAIN SELECT COUNT(*), AVG(fsize)
FROM files FORCE INDEX(ef)
WHERE ext = 'gif' AND filetime >= '2015-01-01'
AND filetime < '2015-01-01' + INTERVAL 1 MONTH;
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
| 1 | SIMPLE | files | range | ef | ef | 14 | NULL | 538 | Using index condition |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
En clair, les rows
dit ef
est mieux. Mais vérifions avec la trace de l'optimiseur. La sortie est plutôt volumineuse; Je ne montrerai que les parties intéressantes. Pas de FORCE
est nécessaire; la trace affichera les deux options puis choisira la meilleure.
...
"potential_range_indices": [
...
{
"index": "fe",
"usable": true,
"key_parts": [
"filetime",
"ext",
"did",
"filename"
]
},
{
"index": "ef",
"usable": true,
"key_parts": [
"ext",
"filetime",
"did",
"filename"
]
}
],
...
"analyzing_range_alternatives": {
"range_scan_alternatives": [
{
"index": "fe",
"ranges": [
"2015-01-01 00:00:00 <= filetime < 2015-02-01 00:00:00"
],
"index_dives_for_eq_ranges": true,
"rowid_ordered": false,
"using_mrr": false,
"index_only": false,
"rows": 16684,
"cost": 20022, <-- Here's the critical number
"chosen": true
},
{
"index": "ef",
"ranges": [
"gif <= ext <= gif AND 2015-01-01 00:00:00 <= filetime < 2015-02-01 00:00:00"
],
"index_dives_for_eq_ranges": true,
"rowid_ordered": false,
"using_mrr": false,
"index_only": false,
"rows": 538,
"cost": 646.61, <-- Here's the critical number
"chosen": true
}
],
...
"attached_conditions_computation": [
{
"access_type_changed": {
"table": "`files`",
"index": "ef",
"old_type": "ref",
"new_type": "range",
"cause": "uses_more_keyparts" <-- Also interesting
}
}
Avec fe
(colonne de plage en premier), la plage pourrait être utilisée, mais elle estime le balayage à travers 16684 lignes de pêche pour ext='gif'
.
Avec ef
(faible cardinalité ext
premier), il pourrait utiliser les deux colonnes de l'index et explorer plus efficacement le BTree. Ensuite, il a trouvé environ 538 lignes, qui sont toutes utiles pour la requête :aucun filtrage supplémentaire n'est nécessaire.
Conclusion :
INDEX(filetime, ext)
utilisé uniquement la première colonne.INDEX(ext, filetime)
utilisé les deux colonnes.- Mettre les colonnes impliquées dans
=
teste d'abord dans l'index indépendamment de la cardinalité . - Le plan de requête n'ira pas au-delà de la première colonne "plage".
- La "cardinalité" n'est pas pertinente pour les index composites et ce type de requête .
("Utiliser la condition d'index" signifie que le moteur de stockage (InnoDB) utilisera des colonnes de l'index au-delà de celle utilisée pour le filtrage.)