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

¿Cómo hago para que MySQL use un ÍNDICE para ver la consulta?

¿Cómo consigues que MySQL use un índice para una consulta de vista? La respuesta corta, proporcione un índice que MySQL pueda usar.

En este caso, el índice óptimo es probablemente un índice de "cobertura":

... ON highscores (player, happened_in, score)

Es probable que MySQL use ese índice, y EXPLAIN mostrará:"Using index" debido al WHERE player = 24 (un predicado de igualdad en la columna inicial del índice. El GROUP BY happened_id (la segunda columna en el índice), puede permitir que MySQL optimice eso usando el índice para evitar una operación de clasificación. Incluyendo la score columna en el índice permitirá que la consulta se satisfaga completamente desde el índice, sin tener que visitar (buscar) las páginas de datos a las que hace referencia el índice.

Esa es la respuesta rápida. La respuesta más larga es que es muy poco probable que MySQL use un índice con una columna inicial de happened_id para la consulta de vista.

Por qué la vista provoca un problema de rendimiento

Uno de los problemas que tiene con la vista de MySQL es que MySQL no "empuja" el predicado de la consulta externa hacia la consulta de vista.

Su consulta externa especifica WHERE happened_in = 2006 . El optimizador de MySQL no considera el predicado cuando ejecuta la "consulta de vista" interna. Esa consulta para la vista se ejecuta por separado, antes de la consulta externa. El conjunto de resultados de la ejecución de esa consulta se "materializa"; es decir, los resultados se almacenan como una tabla MyISAM intermedia. (MySQL lo llama una "tabla derivada", y ese nombre que usan tiene sentido, cuando comprende las operaciones que realiza MysQL).

La conclusión es que el índice que ha definido en happened_in MySQL no lo utiliza cuando ejecuta la consulta que forma la definición de la vista.

Después de crear la "tabla derivada" intermedia, ENTONCES se ejecuta la consulta externa, utilizando esa "tabla derivada" como fuente de fila. Es cuando se ejecuta esa consulta externa que happened_in = 2006 se evalúa el predicado.

Tenga en cuenta que se almacenan todas las filas de la consulta de vista, que (en su caso) es una fila para CADA valor de happened_in , no solo en el que especifica un predicado de igualdad en la consulta externa.

La forma en que se procesan las consultas de vista puede ser "inesperada" para algunos, y esta es una de las razones por las que el uso de "vistas" en MySQL puede generar problemas de rendimiento, en comparación con la forma en que otras bases de datos relacionales procesan las consultas de vista.

Mejorar el rendimiento de la consulta de vista con un índice de cobertura adecuado

Dada la definición de su vista y su consulta, lo mejor que obtendrá sería un método de acceso "Uso de índice" para la consulta de vista. Para obtener eso, necesitaría un índice de cobertura, por ejemplo,

... ON highscores (player, happened_in, score).

Es probable que ese sea el índice más beneficioso (en cuanto al rendimiento) para su definición de vista existente y su consulta existente. El player column es la columna principal porque tiene un predicado de igualdad en esa columna en la consulta de vista. El happened_in la columna es la siguiente, porque tiene una operación GROUP BY en esa columna, y MySQL podrá usar este índice para optimizar la operación GROUP BY. También incluimos la score columna, porque esa es la única otra columna a la que se hace referencia en su consulta. Eso hace que el índice sea un índice de "cobertura", porque MySQL puede satisfacer esa consulta directamente desde las páginas de índice, sin necesidad de visitar ninguna página en la tabla subyacente. Y eso es todo lo bueno que vamos a obtener de ese plan de consulta:"Usar índice" sin "Usar ordenación de archivos".

Compare el rendimiento con una consulta independiente sin una tabla derivada

Puede comparar el plan de ejecución de su consulta con la vista frente a una consulta independiente equivalente:

SELECT player
     , MAX(score) AS highest_score
     , happened_in
 FROM highscores
WHERE player = 24
  AND happened_in = 2006
GROUP
   BY player
    , happened_in

La consulta independiente también puede hacer uso de un índice de cobertura, p.

... ON highscores (player, happened_in, score)

pero sin necesidad de materializar una tabla MyISAM intermedia.

No estoy seguro de que ninguno de los anteriores proporcione una respuesta directa a la pregunta que estabas haciendo.

P:¿Cómo hago para que MySQL use un ÍNDICE para la consulta de vista?

R:Defina un ÍNDICE adecuado que pueda usar la consulta de vista.

La respuesta corta es proporcionar un "índice de cobertura" (el índice incluye todas las columnas a las que se hace referencia en la consulta de vista). Las columnas iniciales en ese índice deben ser las columnas a las que se hace referencia con predicados de igualdad (en su caso, la columna player sería una columna principal porque tienes un player = 24 predicado en la consulta. Además, las columnas a las que se hace referencia en GROUP BY deben ser columnas principales en el índice, lo que permite a MySQL optimizar GROUP BY operación, haciendo uso del índice en lugar de usar una operación de clasificación.

El punto clave aquí es que la consulta de vista es básicamente una consulta independiente; los resultados de esa consulta se almacenan en una tabla "derivada" intermedia (una tabla MyISAM que se crea cuando se ejecuta una consulta en la vista).

Usar vistas en MySQL no es necesariamente una "mala idea", pero les advierto encarecidamente a aquellos que eligen usar vistas dentro de MySQL que sean CONSCIENTE de cómo MySQL procesa las consultas que hacen referencia a esas vistas. Y la forma en que MySQL procesa las consultas de vista difiere (significativamente) de la forma en que otras bases de datos manejan las consultas de vista (por ejemplo, Oracle, SQL Server).