我无法在此发布实际查询,因此我发布了查询的基本大纲,应该足够了。该查询用于分页和返回根据函数输出排序的一组用户,例如F. F从User表和其他连接的表中获取参数。查询如下所示
Select TOP (20)
from (select row_number OVER (Order By F desc) as rownum,
user.*, ..
from user
inner join X on user.blah = X.blah
left outer join Y on user.foo = Y.foo
where DATEDIFF(dd, LastLogin, GetDate()) > 200 and Y.bar > FUBAR) as temp
where rownum > 0
根据执行计划,91%的费用在Sort中。由于排序基于F,我无法添加索引来加快排序速度。内部查询查询所有记录,过滤器然后排序。现在大多数时候用户只看1到5页的结果(1页有20条记录因此Top(20))所以我在想是否有任何方法可以限制正在处理和排序的行大多数时候查询速度更快,CPU密集度更低。
编辑:当我说计算F表加入时,我的意思是这个。 F接受诸如X.blah和Y.foo以及Y.bar之类的参数。而已。所有这些参数也需要作为结果集的一部分返回。例如用户最后位置的纬度和经度存储在X中。
答案 0 :(得分:3)
至少你可以尝试不在每一行调用DATEDIFF
declare @target_date datetime
set @target_date = DATEADD(dd, -200, GetDate())
Select TOP (20)
from (select row_number OVER (Order By F desc) as rownum,
user.*, ..
from user
inner join X on user.blah = X.blah
left outer join Y on user.foo = Y.foo
where LastLogin < @target_date and Y.bar > FUBAR) as temp
where rownum > 0
也许与FUBAR和F做同样的事情?
上面的例子并没有给你太多的性能,但提供了如何减少函数调用的一般想法
答案 1 :(得分:1)
不确定它是否以及它有多大帮助 - 但有两件事:
可以确保WHERE
子句中的所有外键列和列(user.blah
,X.blah
,user.foo
,Y.foo
, Y.bar
)确实被编入索引?这将极大地帮助JOIN表现。
如果这些列未编制索引,则SQL Server使用的执行计划中也可能存在排序操作,因此可以对数据使用合并连接。所以你的排序可能甚至不是来自你认为导致排序的OVER (ORDER BY F DESC)
您正在将TOP (20)
与行号相结合,但您没有为完整的结果集定义任何真实ORDER BY
- 因此您的结果最多是随机的。另外,如果您已定义rownum
,则不能只使用:
SELECT (columns)
FROM (.......) as temp
WHERE rownum BETWEEN 0 AND 20
答案 2 :(得分:1)
一些想法:
F是什么功能?它可以重写为内联表值函数吗?这将使优化器有机会将功能扩展为可重用的执行计划。
您正在Y上执行LEFT OUTER JOIN,但是在WHERE子句中包含Y中的列,有效地将其呈现为INNER JOIN。尽管优化器可能以相同的方式呈现执行计划,但我会将其清理干净,以便将来更容易进行故障排除。