Lassen Sie uns zuerst FORCE INDEX
versuchen um entweder ef
auszuwählen oder fe
. Die Zeiten sind zu kurz, um ein klares Bild davon zu bekommen, was schneller ist, aber `EXPLAIN zeigt einen Unterschied:
Erzwingen des Bereichs auf filetime
Erste. (Hinweis:Die Reihenfolge in WHERE
hat keine Auswirkung.)
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 |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
ext
mit niedriger Kardinalität erzwingen zuerst:
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 |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
Ganz klar die rows
sagt ef
ist besser. Aber lassen Sie uns mit dem Optimizer-Trace nachsehen. Die Ausgabe ist ziemlich sperrig; Ich zeige nur die interessanten Teile. Kein FORCE
wird gebraucht; Der Trace zeigt beide Optionen und wähle dann die bessere aus.
...
"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
}
}
Mit fe
(Bereichsspalte zuerst), der Bereich könnte verwendet werden, aber es wird geschätzt, dass 16684 Zeilen durchsucht werden, die nach ext='gif'
suchen .
Mit ef
(niedrige Kardinalität ext
erstens), könnte es beide Spalten des Index verwenden und effizienter im BTree aufschlüsseln. Dann wurden geschätzte 538 Zeilen gefunden, die alle für die Abfrage nützlich sind – keine weitere Filterung erforderlich.
Schlussfolgerungen:
INDEX(filetime, ext)
nur die erste Spalte verwendet.INDEX(ext, filetime)
beide Spalten verwendet.- Beteiligte Spalten in
=
setzen Tests zuerst im Index unabhängig von der Kardinalität . - Der Abfrageplan geht nicht über die erste 'range'-Spalte hinaus.
- "Kardinalität" ist irrelevant für zusammengesetzte Indizes und diese Art von Abfrage .
("Indexbedingung verwenden" bedeutet, dass die Speicher-Engine (InnoDB) Spalten des Index über die zum Filtern verwendete hinaus verwendet.)