在阅读调优TSQL
查询时,我看到了关于避免(或小心)WHERE
子句中的函数的建议。但是,在某些情况下 - 比如从今天开始需要动态日期的搜索 - 我很好奇是否可以进一步调整查询?例如,下面的查询使用DATEADD
函数作为当前日期,这允许用户随时获取过去30天的正确信息:
SELECT *
FROM Zoo..Transportation
WHERE ArrivalDate BETWEEN DATEADD(DD,-30,GETDATE()) AND GETDATE()
如果我试图消除函数DATEADD
,我可以声明一个变量,该变量将拉动该时间,然后使用存储在变量中的设置值查询数据,例如:
DECLARE @begin DATE
SET @begin = DATEADD(DD,-30,GETDATE())
SELECT *
FROM Zoo..Transportation
WHERE ArrivalDate BETWEEN @begin AND GETDATE()
但是,执行计划和统计显示完全相同的读取,扫描和批量成本。
在动态数据的这些实例中(例如,使用今天的日期作为起点),我们如何减少或消除WHERE
子句中函数的使用?
答案 0 :(得分:5)
where子句中的函数意味着做一些愚蠢的事情:
WHERE DATEPART(WEEK, ArrivalDate) = 1
或者
WHERE CONVERT(CHAR(10), ArrivalDate, 101) = '01/01/2012'
E.g。在where子句中对 columns 的函数,在大多数情况下会破坏sargability(换句话说,渲染索引无用并强制执行索引或表扫描)。
我知道有一个例外:
WHERE CONVERT(DATE, ArrivalDate) = CONVERT(DATE, GETDATE())
但我不会依赖于任何其他情况。
答案 1 :(得分:1)
IME,使用WHERE子句中的函数只是在对查询中的数据进行操作时才会出现问题 - 这意味着函数(本身可能是复杂的SQL)会针对查询中的每个值运行 - 这可能会导致表扫描或类似于optmiser不知道使用哪个索引(如果有)。
上面的示例使用DATEADD和当前日期 - 该值可能计算一次(或者如果为结果集中的每一行计算它,它将不会影响查询计划,因为它不包含来自你的查询)。