sql >> Base de Datos >  >> RDS >> Mysql

SELECCIONAR con variables de consulta que no usan ÍNDICES

La razón radica en el uso de O condiciones en el DONDE cláusula.

Para ilustrar, intente ejecutar la consulta nuevamente, esta vez solo con el id = 5 condición y obtener (resultado de EXPLAIN):

+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+
| id | select_type | table      | type   | possible_keys      | key     | key_len | ref   | rows | Extra          |
+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+
|  1 | PRIMARY     | <derived2> | system | NULL               | NULL    | NULL    | NULL  |    1 |                |
|  1 | PRIMARY     | tree       | const  | PRIMARY,index_both | PRIMARY | 4       | const |    1 |                |
|  2 | DERIVED     | NULL       | NULL   | NULL               | NULL    | NULL    | NULL  | NULL | No tables used |
+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+

Y de nuevo, esta vez solo con parent_id = @last_id OR parent_id = 5 condición y obtener:

+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+
| id | select_type | table      | type   | possible_keys   | key  | key_len | ref  | rows | Extra          |
+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+
|  1 | PRIMARY     | <derived2> | system | NULL            | NULL | NULL    | NULL |    1 |                |
|  1 | PRIMARY     | tree       | ALL    | index_parent_id | NULL | NULL    | NULL |   10 | Using where    |
|  2 | DERIVED     | NULL       | NULL   | NULL            | NULL | NULL    | NULL | NULL | No tables used |
+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+

MySQL no es demasiado bueno para manejar múltiples índices en la misma consulta. Las cosas son un poco mejores con las condiciones AND; uno es más probable que vea un index_merge optimización que una index union optimización.

Las cosas están mejorando a medida que avanzan las versiones, pero he probado tu consulta en la versión 5.5 , que se encuentra en la última versión de producción actual, y los resultados son los que usted describe.

Para explicar por qué esto es difícil, considere:dos índices diferentes responderán a dos condiciones diferentes de la consulta. Uno responderá por id = 5 , el otro para parent_id = @last_id OR parent_id = 5 (Por cierto, no hay problema con O dentro de este último, ya que ambos términos se manejan desde dentro del mismo índice).

No existe un índice único que pueda responder por ambos, y por lo tanto el FORCE INDEX se ignora la instrucción. Véase, FORCE INDEX dice que MySQL tiene que usar an índice sobre un escaneo de tabla. No implica que tenga que usar más de un índice sobre un escaneo de tabla.

Entonces MySQL sigue las reglas de la documentación aquí. Pero, ¿por qué es esto tan complicado? Porque para responder usando ambos índices, MySQL tiene que recopilar resultados de ambos, almacenar uno a un lado en algún búfer temporal mientras administra el segundo. Luego tiene que revisar ese búfer para filtrar filas idénticas (es posible que alguna fila cumpla con todas las condiciones). Y luego escanear ese búfer para devolver los resultados.

Pero espere, ese búfer en sí mismo no está indexado. Filtrar duplicados no es una tarea obvia. Así que MySQL prefiere trabajar en la tabla original y hacer el escaneo allí, y evitar todo ese lío.

Por supuesto que esto tiene solución. Es posible que los ingenieros de Oracle aún mejoren esto (recientemente han estado trabajando arduamente para mejorar los planes de ejecución de consultas), pero no sé si se trata de una tarea TODO o si tiene una alta prioridad.