Först, låt oss försöka FORCE INDEX
för att välja antingen ef
eller fe
. Tiderna är för korta för att få en tydlig bild av vilken som är snabbare, men `EXPLAIN visar en skillnad:
Tvingar intervallet på filetime
först. (Obs:Ordningen i WHERE
har ingen inverkan.)
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 |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
Tvingar fram ext
med låg kardinalitet först:
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 |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
Klart, rows
säger ef
är bättre. Men låt oss kolla med Optimizer-spåret. Utgången är ganska skrymmande; Jag visar bara de intressanta delarna. Ingen FORCE
behövs; spåret visar båda alternativen och välj sedan det bättre.
...
"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
}
}
Med fe
(intervallkolumnen först), intervallet kunde användas, men det uppskattade att skanna genom 16684 rader som fiskade efter ext='gif'
.
Med ef
(låg kardinalitet ext
För det första kan den använda båda kolumnerna i indexet och borra ner mer effektivt i BTree. Sedan hittade den uppskattningsvis 538 rader, som alla är användbara för frågan -- ingen ytterligare filtrering behövs.
Slutsatser:
INDEX(filetime, ext)
använde endast den första kolumnen.INDEX(ext, filetime)
använde båda kolumnerna.- Sätt in kolumner i
=
tester först i indexet oavsett kardinalitet . - Frågeplanen går inte längre än den första kolumnen "intervall".
- "Kardinalitet" är irrelevant för sammansatta index och denna typ av fråga .
("Att använda indexvillkor" betyder att Storage Engine (InnoDB) kommer att använda kolumner i indexet utöver den som används för filtrering.)