迄今为止,可铸造性背后的机制称为动态寻道。
SQL Server调用内部函数GetRangeThroughConvert
来获取范围的开始和结束。
出人意料的是,这是不相同的范围内为您的文字值。
创建一个表,每页一行,每天1440行
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
然后跑步
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';
第一个查询已1443
读取,第二个查询已读取,2883
因此它正在读取整整一整天,然后针对剩余谓词将其丢弃。
计划显示寻找谓词是
Seek Keys[1]: Start: DateTimeCol > Scalar Operator([Expr1006]),
End: DateTimeCol < Scalar Operator([Expr1007])
因此,而不是>= '20130101' ... < '20130102'
读取> '20121231' ... < '20130102'
然后丢弃所有2012-12-31
行。
依赖它的另一个缺点是基数估计可能不如传统范围查询准确。这可以在SQL Fiddle的修订版中看到。
现在,表中的所有100行都与谓词匹配(日期时间在同一天都相隔1分钟)。
第二个(范围)查询正确估计100将匹配并使用聚簇索引扫描。该CAST( AS DATE)
查询错误地估计只有一行会匹配,并生成带有关键查询的计划。
统计信息不会被完全忽略。如果表中的所有行都相同datetime
,并且与谓词(例如20130101 00:00:00
或20130101 01:00:00
)匹配,那么该计划将显示一个聚集索引扫描,估计有31.6228行。
100 ^ 0.75 = 31.6228
因此,在这种情况下,估计值似乎是从此处的公式得出的。
如果表中的所有行都相同datetime
且不匹配谓词(例如20130102 01:00:00
),则它会退回到估计的行数1和带有查找的计划。
对于表具有多个DISTINCT
值的情况,估计的行似乎与查询正在寻找的行相同20130101 00:00:00
。
如果统计直方图恰好有一个台阶,2013-01-01 00:00:00.000
则估计将基于EQ_ROWS
(即不考虑该日期的其他时间)。否则,如果没有任何步骤,则看起来好像使用AVG_RANGE_ROWS
了周围步骤中的。
由于datetime
在许多系统中精度约为3毫秒,因此实际的重复值将很少,而该数字将为1。