2012-02-17 11 views
5

estoy teniendo un MySQL-tabla como la siguiente:Cómo índice de dos columnas de fecha para este tipo de consulta

CREATE TABLE `dates` (
`id` int UNSIGNED NULL AUTO_INCREMENT , 
`object_id` int UNSIGNED NOT NULL , 
`date_from` date NOT NULL , 
`date_to` date NULL , 
`time_from` time NULL , 
`time_to` time NULL , 
PRIMARY KEY (`id`) 
); 

la que se consulta sobre todo de esta manera:

SELECT object_id FROM `dates` 
WHERE NOW() BETWEEN date_from AND date_to 

¿Cómo puedo índice la mejor mesa? ¿Debo crear dos índices, uno para date_from y otro para date_to o es mejor un índice combinado en ambas columnas?

+0

Siento que date_from es mejor para crear el índice en lugar de combinar –

+0

Usted [probablemente] se siente mal. Supongamos que hay 10 filas para algún objeto. 8 tienen una fecha de finalización en el pasado, 1 es "actual" y 1 es "futuro". ¿Cuántos de ellos se filtran por "NOW()> date_from" (respuesta: solo uno) y cuántos se filtran por "NOW()

Respuesta

4

para la consulta:

WHERE NOW() >= date_from 
    AND NOW() <= date_to 

Un índice compuesto (date_from, date_to) es inútil.

Cree ambos índices: (date_from) y (date_to) y deje que el optimizador de SQL decida cada vez cuál usar. Dependiendo de los valores y la selectividad, el optimizador puede elegir uno u otro índice. O ninguno de ellos. No hay una manera fácil de crear un índice que tenga en cuenta ambas condiciones.


(Un índice espacial podría ser utilizado para optimizar tal condición, si se pudiera traducir las fechas a la latitud y longitud).

actualización

Mi error. Un índice en (date_from, date_to, object_id) puede y se usa de hecho en algunas situaciones para esta consulta. Si la selectividad del NOW() <= date_from es lo suficientemente alta, el optimizador elige usar este índice, que haciendo un escaneo completo en la tabla o usando otro índice. Esto se debe a que es un índice de cobertura, lo que significa que no es necesario obtener datos de la tabla, solo se requiere la lectura de los datos del índice.

Nota secundaria (no relacionada con el rendimiento, solo la corrección de la consulta). Su condición es equivalente a:

WHERE CURRENT_DATE() >= date_from 
    AND (CURRENT_DATE() + INTERVAL 1 DAY <= date_to 
     OR (CURRENT_DATE() = NOW() 
     AND CURRENT_DATE() = date_to 
      ) 
    ) 

¿Está seguro de que desea o quiere esto:

WHERE CURRENT_DATE() >= date_from 
    AND CURRENT_DATE() <= date_to 

La función NOW() devuelve un DATETIME, mientras CURRENT_DATE() devuelve un DATE, sin la parte de tiempo.

+0

Gracias por su respuesta, básicamente tengo dos tipos de consulta: o bien estoy seleccionando por 'object_id' para obtener todas las fechas relacionadas para mi objeto o eligiendo un intervalo de fechas donde un día seleccionado (ya sea' NOW() 'o cualquier otra fecha) es entre 'date_from' y' date_to', así que obtengo todas las filas que suceden ese día. – acme

0

Crear un índice con (date_from, date_to) como el único índice sería utilizable para los criterios que en

Si crea índices separados entonces MySQL tendrá que utilizar uno u otro lugar de tanto

1

¿Cuántas filas en relación con el tamaño de su tabla devuelve su consulta? Si es más del 10 por ciento, no me molestaría en crear un índice, en tal caso, de todos modos, está bastante cerca de una exploración de tabla. Si está muy por debajo del 10 por ciento, entonces, en este caso, usaría un índice que contiene (date_from, date_to, object_id) para que el resultado de la consulta pueda construirse completamente a partir de la información en el índice, sin la base de datos para rastrear los datos de la tabla para obtener el valor de object_id.

Según el tamaño de la mesa, esto puede ocupar mucho espacio. Si puedes ahorrar eso, pruébalo.

+0

No sabía que el campo seleccionado luego se toma del índice, ¡es bueno saberlo! Supongo que el recuento de filas es de cinco dígitos y las coincidencias son menos del 10 por ciento. Así que esto parece ser el camino a seguir. – acme

2

Debe crear un índice que cubra date_from, date_to y object_id como lo explica Ypercube. El orden de los campos en el índice depende de si tendrá más datos para el pasado o el futuro. Como señaló Erwin en respuesta al comentario de Sanjay, el campo date_to será más selectivo si tiene más fechas en el pasado y viceversa.

CREATE INDEX ON (date_to, date_from, object_id); 
+0

Ok, ¡gracias por señalar esto! – acme

Cuestiones relacionadas