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
CREATE TABLE T
(
DateTimeCol DATETIME PRIMARY KEY,
Filler CHAR(8000) DEFAULT 'X'
);
WITH Nums(Num)
AS (SELECT number
FROM spt_values
WHERE type = 'P'
AND number BETWEEN 1 AND 1440),
Dates(Date)
AS (SELECT {d '2012-12-30'} UNION ALL
SELECT {d '2012-12-31'} UNION ALL
SELECT {d '2013-01-01'} UNION ALL
SELECT {d '2013-01-02'} UNION ALL
SELECT {d '2013-01-03'})
INSERT INTO T
(DateTimeCol)
SELECT DISTINCT DATEADD(MINUTE, Num, Date)
FROM Nums,
Dates
Então correndo
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
SELECT *
FROM T
WHERE DateTimeCol >= '20130101'
AND DateTimeCol < '20130102'
SELECT *
FROM T
WHERE CAST(DateTimeCol AS DATE) = '20130101';
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 é
Seek Keys[1]: Start: DateTimeCol > Scalar Operator([Expr1006]),
End: DateTimeCol < Scalar Operator([Expr1007])
Então, em vez de >= '20130101' ... < '20130102'
ler > '20121231' ... < '20130102'
, descarta todas as 2012-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
ou 20130101 01:00:00
), o plano mostrará uma varredura de índice em cluster com uma estimativa de 31.6228 linhas.
100 ^ 0.75 = 31.6228
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 exemplo 20130102 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 exatamente 20130101 00:00:00
.
Se ocorrer um passo no histograma estatístico 2013-01-01 00:00:00.000
, a estimativa será baseada no EQ_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 as AVG_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.