2008-11-28 15 views
6

Estoy tratando de encontrar la manera más eficiente (mejor rendimiento) para verificar el campo de fecha para la fecha actual. Actualmente estamos usando:La mejor manera de verificar la fecha actual en donde la cláusula de la consulta sql

SELECT  COUNT(Job) AS Jobs 
FROM   dbo.Job 
WHERE  (Received BETWEEN DATEADD(d, DATEDIFF(d, 0, GETDATE()), 0) 
         AND DATEADD(d, DATEDIFF(d, 0, GETDATE()), 1)) 
+3

Tenga en cuenta que la respuesta que seleccionó NO es la mejor forma de rendimiento.Su camino está cerca de la forma correcta, solo tiene que cambiar a> = y ErikE

Respuesta

10
WHERE 
    DateDiff(d, Received, GETDATE()) = 0 

Edit: como alineados en los comentarios a esta respuesta, eso no es una solución ideal. Verifique las otras respuestas en este hilo, también.

+2

No lo haría de esa manera, ya que no es SARG-able. –

+0

@Mitch Wheat: Mientras no haya una columna con la parte de fecha solamente Y un índice, nada de lo que pueda hacer será SARGable de todos modos. – Tomalak

+1

Tomalak, No - su solución inicial es sargable ... ¿Dónde recibieron> = {} medianoche Esta mañana y recibió <{} la medianoche de hoy es sargable –

0

esa es la mejor manera de hacerlo. podría poner DATEADD (d, DATEDIFF (d, 0, GETDATE()), 0) y DATEADD (d, DATEDIFF (d, 0, GETDATE()), 1) en variables y usarlas en su lugar, pero no lo hago Creo que esto mejorará el rendimiento.

8

Si solo desea encontrar todos los registros donde se encuentra la fecha de recepción, y hay registros con futuras fechas de recepción, entonces lo que está haciendo es (muy ligeramente) incorrecto ... Porque el operador Between permite valores que son iguales al límite final, por lo que podría obtener registros con la fecha Recibido = hasta la medianoche de mañana ...

Si no hay necesidad de utilizar un índice en Recibido, entonces todo lo que necesita hacer es verificar que diff fecha con la fecha y hora actual es 0 ...

Where DateDiff(day, received, getdate()) = 0 

Este predicado por supuesto no es sargable por lo que no puede utilizar un índice ... Si esto es un problema para esta consulta a continuación, suponiendo que no puede haber recibido las fechas en el futuro, me gustaría utilizar este lugar ...

Where Received >= DateAdd(day, DateDiff(Day, 0, getDate()), 0) 

Si las fechas recibidos pueden ser en el futuro, entonces usted está probablemente tan cerca de los más eficientes como puede ser ... (excepto el cambio del Entre a un> = Y <)

+0

Charles, incluso sin el índice, 'DateDiff (día, recibió, getdate())' no es la mejor ya que obliga a un cálculo en cada fila de la tabla, usando más CPU sin ninguna razón. – ErikE

+0

@Emtucifor, cierto, pero en comparación con las lecturas de E/S de disco, los ciclos de CPU son tan insignificantes que son irrelevantes. Estamos hablando de tres a cuatro órdenes de magnitud diferentes aquí. –

+0

Eso es cierto, Charles. Gracias por poner mi nitpicking en perspectiva. :) Creo que es mejor recomendar este último siempre que sea posible, porque cuando hay un índice, eso afectará seriamente a la E/S. – ErikE

0

No estoy seguro de cómo se define "lo mejor", pero funcionará bien.

Sin embargo, si esta consulta es algo que va a ejecutar repetidamente, debería deshacerse de la función get_date() y simplemente colocar un valor de fecha literal allí mediante el lenguaje de programación en el que esté ejecutando esto. A pesar de su el cambio de salida solo una vez cada 24 horas, get_date(), current_date(), etc. son funciones no deterministas, lo que significa que su RDMS probablemente invalidará la consulta como candidato para almacenar en su caché de consultas si tiene una.

0

¿Qué tal

WHERE 
     DATEDIFF(d, Received, GETDATE()) = 0 
+0

Esta no es la mejor manera. Vea la publicación de Marc Gravell de la mejor manera. – ErikE

0

Yo normalmente uso el solution suggested by Tomalak, pero si usted está realmente desesperada para el rendimiento, la mejor opción podría ser añadir un campo indexado adicional ReceivedDataPartOnly - que almacenar datos sin la parte de hora y luego utilizar la consulta

declare @today as datetime 
set @today = datediff(d, 0, getdate()) 

select  
    count(job) as jobs 
from   
    dbo.job 
where  
    received_DatePartOnly = @today 
+0

La solución sugerida por Tomalak está lejos de ser la mejor manera. – ErikE

5

Si desea rendimiento, quieres un golpe directoen el índice, sin ningún tipo de CPU, etc. fila por; como tal, calcularía el rango primero, y luego usaría una consulta WHERE simple. No sé qué db está utilizando, pero en SQL Server, los siguientes trabajos:

// ... where @When is the date-and-time we have (perhaps from GETDATE()) 
DECLARE @DayStart datetime, @DayEnd datetime 
SET @DayStart = CAST(FLOOR(CAST(@When as float)) as datetime) -- get day only 
SET @DayEnd = DATEADD(d, 1, @DayStart) 

SELECT  COUNT(Job) AS Jobs 
FROM   dbo.Job 
WHERE  (Received >= @DayStart AND Received < @DayEnd) 
+0

No estoy seguro de lo que quiere decir con un golpe "directo" en el índice? si simplemente está hablando cuando hay un cálculo en el lado "otro" de un operador de predicado, en lugar de calcularlo antes de ejecutar el índice, entonces A) el valor calculado se basa en alguna otra columna de la tabla y no es lo mismo para la fila generada, por lo que tiene que estar en el SQL, o B) si es el mismo valor para cada fila generada, el procesador de consultas lo calculará previamente de todos modos, por lo que solo se calculará una vez, no importa cuántas filas produce la consulta. –

Cuestiones relacionadas