Laten we eerst FORCE INDEX
proberen om ef
. te kiezen of fe
. De timings zijn te kort om een duidelijk beeld te krijgen van wat sneller is, maar `EXPLAIN laat een verschil zien:
Het bereik forceren op filetime
eerst. (Opmerking:de volgorde in WHERE
heeft geen invloed.)
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 |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
Het forceren van de lage kardinaliteit ext
eerst:
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 |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
Het is duidelijk dat de rows
zegt ef
is beter. Maar laten we eens kijken met de Optimizer-tracering. De uitvoer is nogal omvangrijk; Ik laat alleen de interessante delen zien. Geen FORCE
is nodig; de trace toont beide opties en kies dan de betere.
...
"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
}
}
Met fe
(bereikkolom eerst), het bereik zou kunnen worden gebruikt, maar het schatte scannen door 16684 rijen die op ext='gif'
vissen .
Met ef
(lage kardinaliteit ext
eerst), zou het beide kolommen van de index kunnen gebruiken en efficiënter kunnen inzoomen in de Btree. Toen vond het naar schatting 538 rijen, die allemaal nuttig zijn voor de zoekopdracht - geen verdere filtering nodig.
Conclusies:
INDEX(filetime, ext)
gebruikte alleen de eerste kolom.INDEX(ext, filetime)
beide kolommen gebruikt.- Plaats kolommen die betrokken zijn bij
=
test eerst in de index ongeacht de kardinaliteit . - Het zoekplan gaat niet verder dan de eerste kolom 'bereik'.
- 'Kardinaliteit' is niet relevant voor samengestelde indexen en dit type zoekopdracht .
("Indexvoorwaarde gebruiken" betekent dat de Storage Engine (InnoDB) kolommen van de index gebruikt die verder gaan dan degene die voor filteren wordt gebruikt.)