4

我正在尝试优化一些极其复杂的 SQL 查询,因为它需要很长时间才能完成。

在我的查询中,我使用许多相同的函数动态创建了 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 个这样的查询,这些日期差异是这样计算的。我知道我可以轻松地将它们全部拉入临时表(1,000 个日期差异变为 50 个)-但这值得吗,它会在几秒钟内产生任何影响吗?我希望比十分之一秒的改进更好。

4

3 回答 3

13

老实说,这取决于您正在做什么,以了解性能影响的程度。

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

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

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

不会很好地利用 DateColumn 上的索引。而一个更好的解决方案,提供最佳索引使用将是:

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

如果您有兴趣,我最近在博客上介绍了这带来的差异(通过性能统计/执行计划比较)。

这比将 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, -@AgeAtDate , @Date2)

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

需要补充的一个重要说明是,对于从 DOB 计算的年龄,这种方法更准确。您当前的实施只考虑出生年份,而不是实际日期(例如,2009 年 12 月 1 日出生的人将在 2010 年 1 月 1 日显示为 1 岁,而他们在 2010 年 12 月 1 日之前不是 1 岁)。

希望这可以帮助。

于 2010-03-30T17:49:29.037 回答
0

与其他处理日期时间值的方法(如字符串)相比,DATEDIFF 非常有效。(见这个答案)。

在这种情况下,听起来你一遍又一遍地重复相同的数据,这可能比使用临时表更昂贵。例如,将生成统计信息。

于 2010-03-30T17:56:05.107 回答
0

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

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

于 2010-03-30T19:19:17.763 回答