【问题标题】:Bad performance of SQL query due to ORDER BY clause由于 ORDER BY 子句导致 SQL 查询性能不佳
【发布时间】:2011-01-09 13:05:06
【问题描述】:

我在 WHERE 子句中有一个查询连接了 4 个具有很多条件的表。该查询还包括对数值列的 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

【问题讨论】:

  • 查询计划看过了吗?
  • 尝试为您在 ORDER BY 子句中使用的列建立索引(如果您还没有的话)
  • 还要确保在每次测试之间清除数据/执行计划缓存,否则您可能会得到不正确的结果(最坏的情况是它们实际上执行相同,但第二次运行速度更快)缓存中的数据)。
  • 您实际上并没有在生产代码中使用 select * 是吗?您已经加入,因此您至少要发送重复的数据,这只会浪费网络和服务器资源。永远不要选择比实际需要更多的列,也不要从多个表中选择连接列。
  • 除了索引建议之外,另一个会严重影响性能的因素是数据类型。按整数排序应该比按日期排序快得多,甚至更糟的是 varchar。

标签: sql sql-server sql-server-2005 performance


【解决方案1】:

为什么 order by 会产生如此大的差异以及如何优化它?

ORDER BY 需要对结果集进行排序,如果结果集很大,可能需要很长时间。

要优化它,您可能需要正确索引表。

然而,索引访问路径有其缺点,因此它甚至可能需要更长的时间。

如果您的查询中除了等值连接或范围谓词(如<>BETWEENGROUP 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 作为交叉应用查询的输出,并给它一个别名。它现在要快得多,但也能返回大约 40% 的记录。将不得不进一步调查。
  • @David:我稍微更正了查询,请看帖子更新。 PriceLookupIDPRIMARY KEYOPR_PriceLookup 上吗?
  • 我让它工作了,而且速度要快得多。很高兴了解交叉应用。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2018-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-23
  • 1970-01-01
相关资源
最近更新 更多