由于ORDER BY子句导致SQL查询性能差。

10
我有一个查询需要连接4个表,WHERE子句中有很多条件。查询还包括对数字列的ORDER BY子句。返回结果需要6秒钟,时间太长,我需要加快速度。令人惊讶的是,如果我删除ORDER BY子句,只需要2秒钟。为什么ORDER BY会有如此大的差异,如何进行优化?我使用的是SQL server 2005。非常感谢。
由于我正在清除执行计划缓存,无法确认ORDER BY是否会产生重大影响。然而,您能否解释一下如何稍微加快这个查询的速度?查询如下(为简单起见,“SELECT *”,但我只选择需要的部分)。
SELECT *
FROM View_Product_Joined j 
INNER JOIN [dbo].[OPR_PriceLookup] pl on pl.siteID = NodeSiteID and pl.skuid = j.skuid 
LEFT JOIN [dbo].[OPR_InventoryRules] irp on irp.ID = pl.SkuID and irp.InventoryRulesType = 'Product'
LEFT JOIN [dbo].[OPR_InventoryRules] irs on irs.ID = pl.siteID and irs.InventoryRulesType = 'Store'
WHERE (((((SiteName = N'EcommerceSite') AND (Published = 1)) AND (DocumentCulture = N'en-GB')) AND (NodeAliasPath LIKE N'/Products/Cats/Computers/Computer-servers/%')) AND ((NodeSKUID IS NOT NULL) AND (SKUEnabled = 1) AND pl.PriceLookupID in (select TOP 1 PriceLookupID from OPR_PriceLookup pl2 where pl.skuid = pl2.skuid and (pl2.RoleID = -1 or pl2.RoleId = 13) order by pl2.RoleID desc))) 
ORDER BY NodeOrder ASC

3
你看过查询计划吗? - Jon Skeet
3
尝试对你在ORDER BY子句中使用的列进行索引(如果你还没有这样做的话)。 - davek
2
还要确保在每次测试之间清除数据/执行计划缓存,否则可能会得到扭曲的结果(最坏的情况是它们实际上执行相同,但第二次运行更快,因为它从缓存中获取数据)。 - AdaTheDev
请问您能否同时发布表格定义?不清楚这些字段属于哪些表格。 - Quassnoi
1
你在生产代码中实际上没有使用 select *,是吗?你有连接操作,所以至少会发送重复的数据,这只会浪费网络和服务器资源。永远不要选择比你实际需要的列更多的列,并且不要从多个表中选择连接的列。 - HLGEM
1
除了索引建议之外,还有一件可以极大影响性能的事情就是数据类型。按整数排序应该比按日期排序或者更糟糕的是按字符串排序要快得多。 - Steve Wortham
1个回答

10
为什么使用ORDER BY会产生如此大的差异,如何进行优化?
ORDER BY需要对结果集进行排序,如果结果集很大,则可能需要很长时间。
为了进行优化,您可能需要适当地索引表格。
然而,索引访问路径也有其缺点,因此甚至可能需要更长时间。
如果查询中存在除等值连接之外的内容,或者存在范围谓词(如<、>或BETWEEN或GROUP BY子句),则用于ORDER BY的索引可能会阻止其他索引的使用。
如果您发布查询,我可能会告诉您如何进行优化。
更新:
重写查询:
SELECT  *
FROM    View_Product_Joined j 
LEFT JOIN
        [dbo].[OPR_InventoryRules] irp
ON      irp.ID = j.skuid
        AND irp.InventoryRulesType = 'Product'
LEFT JOIN
        [dbo].[OPR_InventoryRules] irs
ON      irs.ID = j.NodeSiteID
        AND irs.InventoryRulesType = 'Store'
CROSS APPLY
        (
        SELECT  TOP 1 *
        FROM    OPR_PriceLookup pl
        WHERE   pl.siteID = j.NodeSiteID
                AND pl.skuid = j.skuid
                AND pl.RoleID IN (-1, 13)
        ORDER BY
                pl.RoleID desc
        ) pl
WHERE   SiteName = N'EcommerceSite'
        AND Published = 1
        AND DocumentCulture = N'en-GB'
        AND NodeAliasPath LIKE N'/Products/Cats/Computers/Computer-servers/%'
        AND NodeSKUID IS NOT NULL
        AND SKUEnabled = 1
ORDER BY
        NodeOrder ASC

根据名称,关系 View_Product_Joined 可能是一个视图。

请问您能提供它的定义吗?

如果它可以被索引,您可以通过在 View_Product_Joined (SiteName, Published, DocumentCulture, SKUEnabled, NodeOrder) 上创建索引来获得收益。


为了执行查询,我不得不将skuID和siteID作为cross apply查询的输出添加,并给它一个别名。现在速度快了很多,但也返回了约40%的记录。需要进一步调查。 - David
@David:我稍微修改了查询,请查看帖子更新。PriceLookupIDOPR_PriceLookup上是一个PRIMARY KEY吗? - Quassnoi
1
我已经让它正常工作了,而且速度快多了。了解交叉应用是很好的。非常感谢! - David

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接