Primeiro, vamos tentar
FORCE INDEX
para escolher ef
ou fe
. Os tempos são muito curtos para obter uma imagem clara do que é mais rápido, mas `EXPLAIN mostra uma diferença:Forçando o intervalo em
filetime
primeiro. (Observação:A ordem em WHERE
não tem impacto.) 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 |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
Forçando o
ext
de baixa cardinalidade primeiro: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 |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
Claramente, as
rows
diz ef
é melhor. Mas vamos verificar com o rastreamento do Optimizer. A saída é bastante volumosa; Vou mostrar apenas as partes interessantes. Sem FORCE
é preciso; o rastreamento mostrará as duas opções, então escolha a melhor. ...
"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
}
}
Com
fe
(primeiro a coluna de intervalo), o intervalo pode ser usado, mas estimou a varredura de 16.684 linhas pescando ext='gif'
. Com
ef
(baixa cardinalidade ext
primeiro), ele poderia usar ambas as colunas do índice e detalhar com mais eficiência no BTree. Em seguida, encontrou cerca de 538 linhas, todas úteis para a consulta - sem necessidade de filtragem adicional. Conclusões:
INDEX(filetime, ext)
usou apenas a primeira coluna.INDEX(ext, filetime)
usou ambas as colunas.- Coloque as colunas envolvidas em
=
testa primeiro no índice independentemente da cardinalidade . - O plano de consulta não vai além da primeira coluna 'intervalo'.
- "Cardinalidade" é irrelevante para índices compostos e este tipo de consulta .
("Usar condição de índice" significa que o Mecanismo de Armazenamento (InnoDB) usará colunas do índice além daquela usada para filtragem.)