Índice de cobertura utilizado a pesar de la columna faltante

8

Tengo la siguiente consulta, usando MariaDB 10 / InnoDB:

SELECT id, sender_id, receiver_id, thread_id, date_created, content 
FROM user_message 
WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY date_created DESC 
LIMIT 20

Esta consulta recupera mensajes de acuerdo con las condiciones dadas y ordena por fecha de creación.

Tengo un índice de cobertura terminado (thread_id, date_created).

Cuando ejecuto EXPLAIN, se usa el índice correcto y obtengo el resultado "Usando dónde", aunque la consulta está usando una columna en el medio de la declaración que no está en el índice. Puedo usar cualquier valor para "marcador de posición = x" y el resultado es el mismo.

Si cambio la clasificación para usar otra columna, la EXPLICACIÓN indica correctamente "Uso de dónde. Uso de ordenar archivos".

Estoy teniendo un momento de rascarse la cabeza. ¿Alguien podría arrojar luz sobre esto? Lo que esperaría ver es que se necesitaría un clasificador de archivos adicional ya que el índice de cobertura no se pudo usar por completo debido a la columna adicional.

Tom
fuente

Respuestas:

8


Consulta de caso A :

WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY some_column DESC 
LIMIT 20

Índice:

(thread_id, date_created)

Plan:

Index is used
Using Where
Using filesort

No hay problema allí, ¿verdad? Si se usa el índice (para que coincida parcialmente con la WHEREcondición), aún necesitamos una operación de clasificación para ordenar los resultados por some_column(que no está en el índice). También necesitamos una verificación adicional (Uso de Where) para mantener solo las filas que coinciden con la segunda condición. OKAY.


Caso B (la pregunta)
Consulta:

WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY date_created DESC 
LIMIT 20

Índice:

(thread_id, date_created)

Plan:

Index is used
Using Where
-- no "Using filesort"

Entonces, ¿por qué no necesita una especie aquí ? Porque el índice es suficiente para ordenar como la consulta lo desea. Por supuesto, existe el problema adicional de la condición adicional ( AND placeholder = FALSE) que no está cubierta por el índice.

Está bien, pero realmente no necesitamos una especie aquí. El índice nos puede proporcionar resultados que coinciden con la primera condición ( WHERE thread_id = 12345) y están en el orden deseado para la salida. El único control adicional que necesitamos, y lo que hace el plan, es obtener las filas de la tabla, en el orden proporcionado por el índice, y verificar esta segunda condición hasta obtener 20 coincidencias. Eso es lo que significa ** Usando "".

Podemos obtener las 20 coincidencias en las primeras 20 filas (muy buenas y rápidas) o en las primeras 100 (todavía lo suficientemente rápido) o en las primeras 1000000 (probablemente muy, muy lento) o podemos obtener solo 19 coincidencias de tabla incluso después de leer todas las filas coincidentes del índice (realmente muy lento en una tabla grande). Todo depende de la distribución de datos.


Caso C (plan aún mejor)
Consulta:

WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY date_created DESC 
LIMIT 20

Índice:

(placeholder, thread_id, date_created)

Plan:

Index is used
-- no "Using Where"
-- no "Using filesort"

Ahora nuestro índice coincide con ambas condiciones y el orden por. El plan es bastante simple: obtenga las primeras * 20 coincidencias del índice y lea las filas correspondientes de la tabla. No se necesita verificación adicional (No "Usar dónde") ni ordenar (no "Usar ordenar archivos").

primero *: los primeros 20 cuando se lee el índice hacia atrás desde el final (como lo hemos hecho ORDER BY .. DESC) pero eso no es un problema. Los índices del árbol B se pueden leer hacia adelante y hacia atrás con un rendimiento casi igual.

ypercubeᵀᴹ
fuente
7
  • El uso del índice indica un " índice de cobertura ": todas las columnas en cualquier lugar del SELECTestán en cualquier lugar del índice. Por lo tanto, no tiene un índice de "cobertura". Y no es práctico hacer un índice de cobertura para su consulta (se mencionan demasiadas columnas).
  • Usando dónde , principalmente ruido.
  • Uso de ordenar archivos : la consulta necesita una clasificación, pero puede estar en RAM o en una tabla temporal. Y puede haber múltiples tipos (por ejemplo, GROUP BY x ORDER BY b)
  • Cualquiera de estos hará posible mirar solo 20 filas; cualquier otro índice requerirá que se toquen más filas, posiblemente toda la tabla:

    INDEX(thread_id, placeholder, date_created)
    INDEX(placeholder, thread_id, date_created)
    
  • No, la cardinalidad de los componentes de un índice compuesto no importa al ordenar las columnas en el índice.

Mi libro de cocina explica cómo derivar el índice óptimo, dado a SELECT.

Rick James
fuente
Gracias por el libro de cocina, muy buena hoja.
Tom