2010-11-03 12 views
9

Tengo una tabla de MySQL:¿Puede MySQL usar el índice en una RANGE QUERY con ORDER BY?

CREATE TABLE mytable (
    id INT NOT NULL AUTO_INCREMENT, 
    other_id INT NOT NULL, 
    expiration_datetime DATETIME, 
    score INT, 
    PRIMARY KEY (id) 
) 

necesito para ejecutar la consulta en forma de:

SELECT * FROM mytable 
WHERE other_id=1 AND expiration_datetime > NOW() 
ORDER BY score LIMIT 10 

Si añado este índice para Mytable:

CREATE INDEX order_by_index 
ON mytable (other_id, expiration_datetime, score); 

sería MySQL ¿Puedo usar el order_by_index completo en la consulta anterior?

Parece que debería ser capaz de hacerlo, pero entonces de acuerdo con MySQL documentation: "El índice también se puede utilizar incluso si el ORDER BY no coincide con el índice de exactitud, siempre y cuando todas las partes no utilizadas de la index y todas las columnas ORDER BY adicionales son constantes en la cláusula WHERE. "

El pasaje anterior parece sugerir que el índice solo se usaría en una consulta constante mientras que el mío es una consulta de rango.

¿Alguien puede aclarar si el índice se usaría en este caso? Si no, ¿de qué forma podría forzar el uso del índice?

Gracias.

Respuesta

8

MySQL utilizará el índice de satisfacer la cláusula where, y utilizará un filesort para ordenar los resultados.

No puede usar el índice para el pedido porque no está comparando expiration_datetime con una constante. Por lo tanto, las filas que se devuelven no siempre tendrán un prefijo común en el índice, por lo que el índice no se puede usar para la ordenación.

Por ejemplo, considere un conjunto de muestras de los registros 4 de índice para la tabla:

a) [1,'2010-11-03 12:00',1] 
b) [1,'2010-11-03 12:00',3] 
c) [1,'2010-11-03 13:00',2] 
d) [2,'2010-11-03 12:00',1] 

Si me quedo a su consulta el 2010-11-03 11:00, devolverá filas a, c, d que no son consecutivos en el índice. Por lo tanto, MySQL necesita hacer un pase extra para ordenar los resultados y no puede usar un índice en este caso.

+1

>> No se puede utilizar el índice para el fin de porque no se está comparando expiration_datetime a una constante. << Creo que hay un error aquí. Sin embargo, sí explicaste bien la causa de eso en la segunda parte de la respuesta. – kellogs

3

Parece que ya ha revisado la documentación y ha configurado el índice. Utilice explicar y ver ...

EXPLAIN SELECT * FROM mytable 
WHERE other_id=1 AND expiration_datetime > NOW() 
ORDER BY score LIMIT 10 
7

¿Alguien puede aclarar si el índice se usaría en este caso? Si no, ¿de qué forma podría forzar el uso del índice?

Tiene un rango en condiciones de filtrado y el ORDER BY no coincide con el rango.

Estas condiciones no pueden publicarse con un solo índice.

Para elegir qué índice de crear, es necesario ejecutar estas consultas

SELECT COUNT(*) 
FROM mytable 
WHERE other_id = 1 
     AND (score, id) < 
     (
     SELECT score, id 
     FROM mytable 
     WHERE other_id = 1 
       AND expiration_datetime > NOW() 
     ORDER BY 
       score, id 
     LIMIT 10 
     ) 

y

SELECT COUNT(*) 
FROM mytable 
WHERE other_id = 1 
     AND expiration_datetime >= NOW() 

y comparar sus salidas.

Si la segunda consulta arroja aproximadamente el mismo valor o más que el primero, entonces debe usar un índice en (other_id, score) (y dejar que se filtre en expiration_datetime).

Si la segunda consulta arroja valores significativamente menores que la primera, debe usar un índice en (other_id, expiration_datetime) (y deje que se ordene en score).

Este artículo podría ser interesante para usted:

+0

Para verificar la selectividad necesita verificar valores distintos, así que no olvide hacer COUNT DISTINCT. –

+0

@AllTheCode: 'COUNT DISTINCT' en qué? – Quassnoi

Cuestiones relacionadas