表达对列
首先,不管你用什么样的功能,把它在WHERE子句中或JOIN条件中对表中的一列是次优的。做一个常数的数学和比较。您的WHERE子句中应该是这样的:
ff.startDate < DateAdd(day, 1, @curdate) -- if @curdate has time portion removed
ff.startDate < DateAdd(day, 1, dbo.fn_GetDateOnly(@curdate)) -- if @curdate has time
对于在给定日期一般寻找项目,使用这个模式:
WHERE
DateCol >= '20120901'
AND DateCol < '20120902'
把任何功能上等号的另一侧列,这应该是孤独的。它可以帮助你查找如何使一个表达式SARGABLE。如果列必须位于两侧,则将所有表达式放在执行计划中“左”输入的一侧(其数据先到达,LOOP JOIN的外循环或一个LOOP JOIN的“表”一侧哈希连接)。例如,如果你想做到这一点:
WHERE dbo.fn_getDateOnly(A.DateCol) = dbo.fn_getDateOnly(B.DateCol)
然后假设A.DateCol至上在执行计划中,切换到:
WHERE
B.DateCol >= DateAdd(day, DateDiff(day, 0, A.DateCol), 0)
AND B.DateCol < DateAdd(day, DateDiff(day, 0, A.DateCol), 0)
(或使用内嵌版本函数如下,但我觉得它是尴尬的,所以没有额外的价值是间接的)。
如果这种查询将在所涉及的表上频繁进行,那么可能需要重新设计一些重新设计,或者添加一个删除了时间部分(可能被索引)的持久计算列,以便将日期时间转换为单独的日期和时间字段,或将其存储为开头的日期(如果您确实不需要日期时间)。
注意:当然,对dbo.fn_getDateOnly的引用可以简单地替换为DateAdd(day, DateDiff(day, 0, DateCol), 0)
。此外,如果值为datetime
数据类型,则只需执行DateCol + 1
而不是使用DateAdd
(不过要小心,因为这对于SQL 2008和更高版本中的date
数据类型不起作用)。
的UDF
的直列能力对于SELECT子句中的函数的性能,SQL Server只内联“内联函数”,而不是标量函数。改变你的函数返回一个单行记录CREATE FUNCTION ... RETURNS TABLE AS RETURN (SELECT ...)
,并使用它,像这样:
SELECT
(SELECT DateValue FROM dbo.fn_GetDateOnly(Col)),
...
这真的是不超过一个参数化的视图不同。
在WHERE子句中使用这个内联版本会变得笨拙。做DateDiff几乎更好。在SQL 2008中,当然只是使用Convert(date, DateCol)
,但仍然遵循关于在哪里放置计算表达式(与列中等号相反的一侧)的规则。
一定要投票inline scalar UDFs on Microsoft Connect!你远离唯一一个认为这个功能非常缺乏的人。
如果可能的话,您应该尽量避免围绕列进行任何类型的函数调用。 'WHERE ff.startDate
2012-07-23 15:45:07