Essas duas consultas são logicamente equivalentes?

10

Essas duas consultas são logicamente equivalentes?

DECLARE @DateTime DATETIME = GETDATE()

Consulta 1

SELECT *
FROM   MyTable
WHERE  Datediff(DAY, LogInsertTime, @DateTime) > 7   

Consulta 2

SELECT *
FROM   MyTable
WHERE  LogInsertTime < @DateTime - 7 

Se eles não forem logicamente equivalentes, você pode me fornecer o equivalente lógico da primeira consulta para que a cláusula WHERE possa efetivamente usar um índice (por exemplo, eliminar o agrupamento de funções)?

Alf47
fonte
Que tipo LogInsertTimeé
Dez17
11
Dê uma olhada em knowdotnet.com/articles/getdatereturn.html .
A1ex07 17/10/12
LogInsertTime é um DATETIME
Alf47

Respostas:

15

Se as duas consultas que você postou são logicamente equivalentes é irrelevante; você não deve usar nenhum deles. Vou tentar afastar você de algumas coisas:

  1. Sempre que possível, tente evitar aplicar funções às colunas. É sempre tão bom, e principalmente melhor, manter esses cálculos contra constantes e não colunas - isso pode destruir a SARGability e tornar inúteis os índices nessas colunas. Nesse caso, eu prefiro a consulta 2, especialmente se LogDateTimeestiver indexada (ou pode estar).
  2. Eu não gosto da matemática da taquigrafia e recomendo contra ela. Claro, é mais rápido digitar, mas tente isso com um DATEtipo de dados e você receberá um erro feio. Muito melhor explicitar, por exemplo:

    WHERE LogInsertTime < DATEADD(DAY, -7, @DateTime);
Aaron Bertrand
fonte
Concordo que meu objetivo era alterar a consulta 1 em algo semelhante à consulta 2 para que os índices pudessem ser usados ​​com eficácia. Obrigado pela ajuda.
Alf47 17/10/12
8

Eu usaria a seguinte consulta sargível:

SELECT * FROM MyTable WHERE LogInsertTime < DATEADD(DAY, -7, @DateTime)

O motivo: acredito que o resultado do @ DateTime-7 não está documentado. Mesmo que isso seja equivalente a DATEADD (DAY, -7, @DateTime), ele poderá ser interrompido em uma versão posterior.

AK
fonte
Grande que é exatamente o que eu estava procurando, obrigado
Alf47
2
É, de fato, documentada e bem definida : - (Subtract): Subtracts two numbers (an arithmetic subtraction operator). Can also subtract a number, in days, from a date.. Ainda assim, concordo que o uso de funções explícitas de data torna a consulta resultante mais legível e mantida do que a "mágica do operador aritmético".
Heinzi
6

Eles não são equivalentes. Os registros 7 dias atrás, mas antes da hora atual do dia - serão retornados somente na consulta 2:

Ao comparar os dias usando a DATEADDfunção , ela não leva em consideração a parte do tempo . A função retornará 1 ao comparar domingo e segunda-feira, independentemente dos horários.

Demo:

DECLARE @MyTable TABLE(pk INT, LogInsertTime DATETIME);

INSERT @MyTable
VALUES (1, DATEADD(HOUR, 1, CAST(DATEADD(DAY, -7, CAST (GETDATE() AS DATE))AS DATETIME))),
(2, DATEADD(HOUR, 23, CAST(DATEADD(DAY, -7, CAST (GETDATE() AS DATE)) AS DATETIME)));

DECLARE @DateTime DATETIME = GETDATE();

SELECT *
FROM @MyTable
WHERE DATEDIFF(DAY, LogInsertTime, @DateTime) > 7;

-- 0 records.

SELECT *
FROM @MyTable
WHERE LogInsertTime < @DateTime - 7;
-- 1 record.

O equivalente lógico da primeira consulta que permitirá o uso potencial do índice é remover a parte da hora @DateTimeou definir a hora para 0:00:00:

SELECT *
FROM @MyTable
WHERE LogInsertTime < CAST(@DateTime - 7 AS DATE);

A razão pela qual a primeira consulta não pode usar um índice LogInsertTimeé porque a coluna está oculta dentro de uma função. A consulta 2 compara a coluna a um valor constante que permite ao otimizador escolher um índice LogInsertTime.

The Scrum Meister
fonte