sql-server – Cast to date是sargable,但这是个好主意吗?

sql Server 2008中添加date数据类型.

到目前为止,将datetime列转换为sargable,可以使用datetime列上的索引.

select *
from T
where cast(DateTimeCol as date) = '20130101';

您拥有的另一个选择是使用范围.

select *
from T
where DateTimeCol >= '20130101' and
      DateTimeCol < '20130102'

这些查询是同样好还是应该优先于另一个

解决方法

到目前为止,铸造的可焊性背后的机制称为 dynamic seek.

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)查询错误地估计只有一行匹配并生成带有键查找的计划.

统计数据不会完全被忽略.如果表中的所有行具有相同的日期时间并且它与谓词匹配(例如20130101 00:00:00或20130101 01:00:00),则计划显示聚集索引扫描,估计行数为31.6228.

100 ^ 0.75 = 31.6228

因此,在这种情况下,估计似乎是从the formula here得出的.

如果表中的所有行具有相同的日期时间且与谓词不匹配(例如20130102 01:00:00),则它将回退到估计的行数1和具有查找的计划.

对于表具有多个disTINCT值的情况,估计的行似乎与查询正在查找20130101 00:00:00完全相同.

如果统计直方图恰好在2013-01-01 00:00:00.000处有一个步骤,则估计将基于EQ_ROWS(即不考虑该日期的其他时间).否则,如果没有步骤,它看起来好像是使用周围步骤中的AVG_RANGE_ROWS.

由于日期时间在许多系统中的精度约为3毫秒,因此实际重复值非常少,此数字为1.

相关文章

SELECT a.*,b.dp_name,c.pa_name,fm_name=(CASE WHEN a.fm_n...
if not exists(select name from syscolumns where name=&am...
select a.*,pano=a.pa_no,b.pa_name,f.dp_name,e.fw_state_n...
要在 SQL Server 2019 中设置定时自动重启,可以使用 Window...
您收到的错误消息表明数据库 &#39;EastRiver&#39; 的...
首先我需要查询出需要使用SQL Server Profiler跟踪的数据库标...