En SQL Server 2008, se agregó el tipo de datos de fecha .
La conversión de una datetime
columna a date
es sargable y puede usar un índice en la datetime
columna.
select *
from T
where cast(DateTimeCol as date) = '20130101';
La otra opción que tiene es usar un rango en su lugar.
select *
from T
where DateTimeCol >= '20130101' and
DateTimeCol < '20130102'
¿Son estas consultas igualmente buenas o debería preferirse una sobre la otra?
sql-server
Mikael Eriksson
fuente
fuente
where cast(date_column as date) = 'value'
cuando se presenta con C # similar awhere obj.date_column.Date == date_variable
.Respuestas:
El mecanismo detrás de la sargabilidad del casting hasta la fecha se llama búsqueda dinámica .
SQL Server llama a una función interna
GetRangeThroughConvert
para obtener el inicio y el final del rango.Sorprendentemente, este no es el mismo rango que sus valores literales.
Crear una tabla con una fila por página y 1440 filas por día
Entonces corriendo
La primera consulta tiene
1443
lecturas y la segunda,2883
por lo que lee un día adicional completo y luego la descarta contra un predicado residual.El plan muestra que el predicado de búsqueda es
Entonces, en lugar de
>= '20130101' ... < '20130102'
leer,> '20121231' ... < '20130102'
luego descarta todas las2012-12-31
filas.Otra desventaja de confiar en él es que las estimaciones de cardinalidad pueden no ser tan precisas como con la consulta de rango tradicional. Esto se puede ver en una versión modificada de su SQL Fiddle .
Las 100 filas de la tabla ahora coinciden con el predicado (con fecha y hora con 1 minuto de diferencia, todo en el mismo día).
La segunda consulta (rango) estima correctamente que 100 coincidirán y utiliza un escaneo de índice agrupado. La
CAST( AS DATE)
consulta estima incorrectamente que solo una fila coincidirá y produce un plan con búsquedas clave.Las estadísticas no se ignoran por completo. Si todas las filas de la tabla tienen el mismo
datetime
y coincide con el predicado (por ejemplo,20130101 00:00:00
o20130101 01:00:00
), el plan muestra un análisis de índice agrupado con un estimado de 31.6228 filas.Entonces, en ese caso, parece que la estimación se deriva de la fórmula aquí .
Si todas las filas de la tabla tienen el mismo
datetime
y no coincide con el predicado (p20130102 01:00:00
. Ej. ), Vuelve al recuento de filas estimado de 1 y al plan con búsquedas.Para los casos en que la tabla tiene más de un
DISTINCT
valor, las filas estimadas parecen ser las mismas que si la consulta estuviera buscando exactamente20130101 00:00:00
.Si el histograma de estadísticas tiene un paso,
2013-01-01 00:00:00.000
entonces la estimación se basará enEQ_ROWS
(es decir, sin tener en cuenta otras veces en esa fecha). De lo contrario, si no hay un paso, parece que usa elAVG_RANGE_ROWS
de los pasos circundantes.Como
datetime
tiene una precisión de aproximadamente 3 ms en muchos sistemas, habrá muy pocos valores duplicados reales y este número será 1.fuente
TL;DR
parte con algunos puntos con diferentes casos agregando si en ese caso, el reparto hasta la fecha es una buena idea o no?Sé que tiene una gran respuesta de Martin desde hace mucho tiempo, pero quería agregar algunos cambios al comportamiento aquí en las versiones más recientes de SQL Server. Esto parece haber sido probado hasta 2008R2.
Con las nuevas SUGERENCIAS DE USO que hacen posible realizar un viaje en el tiempo de estimación de cardinalidad, podemos ver cuándo cambiaron las cosas.
Usando la misma configuración que en el Fiddle de SQL.
Podemos probar los diferentes niveles así:
Los planes para todo esto están disponibles aquí . Los niveles de compatibilidad 100 y 110 proporcionan el plan de búsqueda clave, pero a partir del nivel de compatibilidad 120, comenzamos a obtener el mismo plan de exploración con estimaciones de 100 filas. Esto es cierto hasta el nivel de compatibilidad 140.
La estimación de la cardinalidad para los
>= '20130101', < '20130102'
planes se mantiene en 100, lo que se esperaba.fuente