Primero, probemos FORCE INDEX
para elegir ef
o fe
. Los tiempos son demasiado cortos para obtener una imagen clara de cuál es más rápido, pero 'EXPLAIN muestra una diferencia:
Forzar el rango en filetime
primero. (Nota:El orden en WHERE
no tiene 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 |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
Forzar la cardinalidad baja ext
primero:
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, las rows
dice ef
es mejor. Pero verifiquemos con el seguimiento del Optimizer. La salida es bastante voluminosa; Voy a mostrar sólo las partes interesantes. Sin FORCE
se necesita; el seguimiento mostrará ambas opciones y luego elegirá la mejor.
...
"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
}
}
Con fe
(columna de rango primero), se podría usar el rango, pero estimó escanear a través de 16684 filas pescando ext='gif'
.
Con ef
(baja cardinalidad ext
primero), podría usar ambas columnas del índice y profundizar de manera más eficiente en el BTree. Luego encontró un estimado de 538 filas, todas las cuales son útiles para la consulta, no se necesita más filtrado.
Conclusiones:
INDEX(filetime, ext)
usó solo la primera columna.INDEX(ext, filetime)
usó ambas columnas.- Poner columnas involucradas en
=
pruebas primero en el índice independientemente de la cardinalidad . - El plan de consulta no irá más allá de la primera columna de 'rango'.
- "Cardinalidad" es irrelevante para índices compuestos y este tipo de consulta .
("Usar la condición de índice" significa que el motor de almacenamiento (InnoDB) utilizará columnas del índice más allá de la utilizada para el filtrado).