No SQL Server 2008, o tipo de dados de data foi adicionado.
A conversão de uma datetime
coluna para date
é sargável e pode usar um índice na datetime
coluna.
select *
from T
where cast(DateTimeCol as date) = '20130101';
A outra opção que você tem é usar um intervalo.
select *
from T
where DateTimeCol >= '20130101' and
DateTimeCol < '20130102'
Essas consultas são igualmente boas ou uma deve ser preferida à outra?
O mecanismo por trás da sargabilidade do casting até hoje é chamado de busca dinâmica .
O SQL Server chama uma função interna
GetRangeThroughConvert
para obter o início e o fim do intervalo.Surpreendentemente, este não é o mesmo intervalo que seus valores literais.
Criando uma tabela com uma linha por página e 1440 linhas por dia
Em seguida, correndo
A primeira consulta tem
1443
leituras e a segunda2883
, portanto, está lendo um dia adicional inteiro e, em seguida, descartando-o contra um predicado residual.O plano mostra que o predicado de busca é
Então, em vez de
>= '20130101' ... < '20130102'
ler> '20121231' ... < '20130102'
, descarta todas as2012-12-31
linhas.Outra desvantagem de confiar nele é que as estimativas de cardinalidade podem não ser tão precisas quanto na consulta de intervalo tradicional. Isso pode ser visto em uma versão corrigida do seu SQL Fiddle .
Todas as 100 linhas na tabela agora correspondem ao predicado (com datas e horas separadas por 1 minuto, todas no mesmo dia).
A segunda consulta (intervalo) estima corretamente que 100 corresponderá e usa uma verificação de índice clusterizado. A
CAST( AS DATE)
consulta estima incorretamente que apenas uma linha corresponderá e produz um plano com pesquisas de chave.As estatísticas não são completamente ignoradas. Se todas as linhas na tabela tiverem o mesmo
datetime
e corresponderem ao predicado (por exemplo ,20130101 00:00:00
ou20130101 01:00:00
), o plano mostrará uma varredura de índice clusterizado com 31,6228 linhas estimadas.Portanto, nesse caso, parece que a estimativa é derivada desta fórmula :
Se todas as linhas na tabela tiverem o mesmo
datetime
e não corresponderem ao predicado (por exemplo20130102 01:00:00
, ), ele retornará à contagem de linhas estimada de 1 e ao plano com pesquisas.Para os casos em que a tabela possui mais de um
DISTINCT
valor, as linhas estimadas parecem ser as mesmas como se a consulta estivesse procurando exatamente20130101 00:00:00
.Se o histograma estatístico tiver um passo em
2013-01-01 00:00:00.000
então a estimativa será baseada noEQ_ROWS
(ou seja, não levando em consideração outros horários naquela data). Caso contrário, se não houver nenhuma etapa, parece que ele usa asAVG_RANGE_ROWS
etapas ao redor.Como
datetime
tem uma precisão de aproximadamente 3 ms em muitos sistemas, haverá muito poucos valores reais duplicados e esse número será 1.Eu sei que isso tem uma Great Answer® de longa data de Martin, mas eu queria adicionar algumas mudanças no comportamento aqui em versões mais recentes do SQL Server. Isso parece ter sido testado apenas até 2008R2.
Com as novas USE HINTs que possibilitam algumas viagens no tempo de estimativa de cardinalidade, podemos ver quando as coisas mudaram.
Usando a mesma configuração do SQL Fiddle.
Podemos testar os diferentes níveis assim:
Os planos para todos eles estão disponíveis aqui . Os níveis de compatibilidade 100 e 110 fornecem o plano de pesquisa de chave, mas começando com o nível de compatibilidade 120, começamos a obter o mesmo plano de varredura com estimativas de 100 linhas. Isso é verdade até o nível de compatibilidade 150.
A estimativa de cardinalidade para os
>= '20130101', < '20130102'
planos permanece em 100, o que era esperado.