No SQL Server 2008, o tipo de dados da data foi adicionado.
A transmissão de uma datetime
coluna para date
é sargable 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?
sql-server
Mikael Eriksson
fonte
fonte
where cast(date_column as date) = 'value'
quando apresentado com C # semelhante awhere obj.date_column.Date == date_variable
.Respostas:
O mecanismo por trás da sargabilidade da transmissão até o momento é chamado busca dinâmica .
O SQL Server chama uma função interna
GetRangeThroughConvert
para obter o início e o fim do intervalo.Surpreendentemente, esse não é o mesmo intervalo que seus valores literais.
Criando uma tabela com uma linha por página e 1440 linhas por dia
Então correndo
A primeira consulta possui
1443
leituras e a segunda,2883
portanto, está lendo um dia adicional inteiro e descartando-a 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 nisso é 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 alterada do seu SQL Fiddle .
Todas as 100 linhas da tabela agora correspondem ao predicado (com datas de 1 minuto, todas no mesmo dia).
A segunda consulta (intervalo) estima corretamente que 100 corresponderá e usa uma verificação de índice em cluster. A
CAST( AS DATE)
consulta calcula incorretamente que apenas uma linha corresponderá e produzirá um plano com as principais pesquisas.As estatísticas não são completamente ignoradas. Se todas as linhas da 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 em cluster com uma estimativa de 31.6228 linhas.Portanto, nesse caso, parece que a estimativa é derivada da fórmula aqui .
Se todas as linhas da 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.Nos casos em que a tabela possui mais de um
DISTINCT
valor, as linhas estimadas parecem iguais, como se a consulta estivesse procurando exatamente20130101 00:00:00
.Se ocorrer um passo no histograma estatístico
2013-01-01 00:00:00.000
, a estimativa será baseada noEQ_ROWS
(ou seja, não levando em consideração outros momentos nessa data). Caso contrário, se não houver etapa, parece que ela usa asAVG_RANGE_ROWS
etapas anteriores.Como
datetime
tem uma precisão de aproximadamente 3ms em muitos sistemas, haverá muito poucos valores duplicados reais e esse número será 1.fonte
TL;DR
parte com alguns pontos de bala com casos diferentes, adicionando se, nesse caso, o elenco até hoje é uma boa ideia ou não?Eu sei que isso tem uma excelente resposta de longa data de Martin, mas eu queria adicionar algumas alterações no comportamento aqui nas versões mais recentes do SQL Server. Parece que apenas foi testado até 2008R2.
Com as novas DICAS DE USO que tornam possível realizar alguma viagem no tempo com estimativa de cardinalidade, podemos ver quando as coisas mudaram.
Usando a mesma configuração do SQL Fiddle.
Podemos testar os diferentes níveis da seguinte forma:
Os planos para todos estes estão disponíveis aqui . Os níveis de compatibilidade 100 e 110 fornecem o plano de pesquisa principal, mas a partir do nível 120, começamos a obter o mesmo plano de varredura com estimativas de 100 linhas. Isso é verdade até o nível 140 compatível.
A estimativa de cardinalidade para os
>= '20130101', < '20130102'
planos permanece em 100, o que era esperado.fonte