2010-03-30 99 views
4

我试图优化一些可怕的复杂的SQL查询,因为它需要很长时间才能完成。SQL DATEDIFF(年,...,...)昂贵的计算?

在我的查询中,我用很多相同的函数动态地创建了SQL语句,所以我创建了一个临时表,其中每个函数只被调用一次而不是很多次 - 这将我的执行时间减少了3/4 。

所以我的问题是,我可以期待看到很大的差异,如果说,1,000个datediff计算缩小到100?

编辑: 查询看起来像这样:

SELECT DISTINCT M.MID, M.RE FROM #TEMP INNER JOIN M ON #TEMP.MID=M.MID 
WHERE (#TEMP.Property1=1) AND 
DATEDIFF(year, M.DOB, @date2) >= 15 AND DATEDIFF(year, M.DOB, @date2) <= 17 

其中这些被动态生成的作为字符串(一起放在星星点点),然后执行,使得各种参数可以沿着每个迭代被改变 - 主要是最后一行,包含各种DATEDIFF查询。

这里约有420个查询,其中这些datediffs的计算方式如此。我知道我可以很容易地将它们全部放入临时表中(1,000年以上),但它是否值得,它会在几秒钟内发生什么变化?我希望比十分之几秒有更好的改善。

+3

发布查询 - 确实无法帮助您确认在2深度子查询中执行DATEDIFF时的假设... – 2010-03-30 17:46:49

回答

13

这完全取决于您所做的事情,以诚实的方式表现。

例如,如果您在WHERE子句中使用DATEDIFF(或实际上任何其他函数),那么这将成为性能较差的原因,因为它会阻止在该列上使用索引。

例如基本示例,查找2009年的所有记录

WHERE DATEDIFF(yyyy, DateColumn, '2009-01-01') = 0 

不能很好地使用DateColumn上的索引。而一个更好的解决方案,提供最佳的指数用法是:

WHERE DateColumn >= '2009-01-01' AND DateColumn < '2010-01-01' 

recently blogged有关这使得(与性能统计/执行计划比较),如果你有兴趣的差异。

这比将DATEDIFF作为结果集中的列返回的代价要昂贵。

我会从识别花费时间最多的单个查询开始。检查执行计划,看看问题出在哪里,然后从那里调整。

编辑: 根据您给出的示例查询,您可以尝试在WHERE子句中删除DATEDIFF的使用。在给定日期找到每个10岁的人的基本示例 - 我认为数学是正确的,但无论如何你都明白了!给它一个快速测试,并且看起来很好。应该很容易适应你的情况。如果您想查找某个日期的(例如)15岁和17岁之间的人,那么使用此方法也可以。

-- Assuming @Date2 is set to the date at which you want to calculate someone's age 
DECLARE @AgeAtDate INTEGER 
SET @AgeAtDate = 10 

DECLARE @BornFrom DATETIME 
DECLARE @BornUntil DATETIME 
SELECT @BornFrom = DATEADD(yyyy, -(@AgeAtDate + 1), @Date2) 
SELECT @BornUntil = DATEADD(yyyy, [email protected] , @Date2) 

SELECT DOB 
FROM YourTable 
WHERE DOB > @BornFrom AND DOB <= @BornUntil 

需要补充的一个重要注意事项是来自DOB的年龄计算,这种方法更准确。您目前的实施只考虑出生年份,而不是实际的一天(例如,2009年12月1日出生的人将在2010年1月1日出现1岁,直到2010年12月1日不是1岁)。

希望这会有所帮助。

+2

正确,当然这适用于几乎* any *函数用于包装索引列,不只是'DATEDIFF'。 – Aaronaught 2010-03-30 18:02:08

+0

@Aarounaught - 是的,谢谢你的收获。我已经更新了我的答案,以便更明确 – AdaTheDev 2010-03-30 18:05:02

+0

是的,很好的答案 – HLGEM 2010-03-30 19:17:38

0

与其他处理日期时间值的方法(如字符串)相比,DATEDIFF相当高效。 (see this SO answer)。

在这种情况下,您听起来像是在翻阅相同的数据,这可能比使用临时表更昂贵。例如,将生成统计信息。

0

您可能可以做的一件事是提高性能,可能是在MID的临时表上放置一个索引。

检查您的执行计划,看看它是否有帮助(可能取决于临时表中的行数)。