sql-server – 如何优化嵌套循环运行缓慢的查询(内部联接)

前端之家收集整理的这篇文章主要介绍了sql-server – 如何优化嵌套循环运行缓慢的查询(内部联接)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
TL; DR

既然这个问题不断得到意见,我会在这里总结一下,所以新人不必忍受历史:

JOIN table t ON t.member = @value1 OR t.member = @value2 -- this is slow as hell
JOIN table t ON t.member = COALESCE(@value1,@value2)    -- this is blazing fast
-- Note that here if @value1 has a value,@value2 is NULL,and vice versa

我意识到这可能并非每个人都有问题,但通过强调ON子句的敏感性,它可能会帮助您朝着正确的方向前进.在任何情况下,原始文本都在这里供未来的人类学家使用:

原文

考虑以下简单查询(仅涉及3个表)

SELECT

        l.sku_id AS ProductId,l.is_primary AS IsPrimary,v1.category_name AS Category1,v2.category_name AS Category2,v3.category_name AS Category3,v4.category_name AS Category4,v5.category_name AS Category5

    FROM category c4
    JOIN category_voc v4 ON v4.category_id = c4.category_id and v4.language_code = 'en'

    JOIN category c3 ON c3.category_id = c4.parent_category_id
    JOIN category_voc v3 ON v3.category_id = c3.category_id and v3.language_code = 'en'

    JOIN category c2 ON c2.category_id = c3.category_id
    JOIN category_voc v2 ON v2.category_id = c2.category_id and v2.language_code = 'en'

    JOIN category c1 ON c1.category_id = c2.parent_category_id
    JOIN category_voc v1 ON v1.category_id = c1.category_id and v1.language_code = 'en'

    LEFT OUTER JOIN category c5 ON c5.parent_category_id = c4.category_id
    LEFT OUTER JOIN category_voc v5 ON v5.category_id = c5.category_id and v5.language_code = @lang

    JOIN category_link l on l.sku_id IN (SELECT value FROM #Ids) AND
    (
        l.category_id = c4.category_id OR
        l.category_id = c5.category_id
    )

    WHERE c4.[level] = 4 AND c4.version_id = 5

这是一个非常简单的查询,唯一令人困惑的部分是最后一个类别连接,这是因为类别级别5可能存在也可能不存在.在查询结束时,我正在寻找每个产品ID(SKU ID)的类别信息,以及那个非常大的表category_link的位置.最后,表#Ids只是一个包含10’000 ID的临时表.

执行时,我得到以下实际执行计划:

如您所见,几乎90%的时间都花在了嵌套循环(内部连接)上.以下是有关嵌套循环的额外信息:

请注意,表名称不完全匹配,因为我编辑了查询名称以便于阅读,但它很容易匹配(ads_alt_category = category).有没有办法优化这个查询?另请注意,在生产中,临时表#Ids不存在,它是传递给存储过程的相同10’000个ID的表值参数.

附加信息:

> category_id和parent_category_id上的类别索引
> category_id,language_code上的category_voc索引
> sku_id,category_id上的category_link索引

编辑(已解决)

正如接受的答案所指出的那样,问题是category_link JOIN中的OR子句.但是,在接受的答案中建议的代码非常慢,甚至比原始代码慢.更快,更清洁的解决方案就是用以下内容替换当前的JOIN条件:

JOIN category_link l on l.sku_id IN (SELECT value FROM @p1) AND l.category_id = COALESCE(c5.category_id,c4.category_id)

这一分钟调整是最快的解决方案,根据接受的答案对双连接进行测试,并根据valverij的建议对CROSS APPLY进行测试.

解决方法

问题似乎出现在这部分代码中:
JOIN category_link l on l.sku_id IN (SELECT value FROM #Ids) AND
(
    l.category_id = c4.category_id OR
    l.category_id = c5.category_id
)

或者在加入条件下总是可疑的.一个建议是将其拆分为两个连接:

JOIN category_link l1 on l1.sku_id in (SELECT value FROM #Ids) and l1.category_id = cr.category_id
left outer join
category_link l1 on l2.sku_id in (SELECT value FROM #Ids) and l2.category_id = cr.category_id

然后,您必须修改查询的其余部分以处理此问题. . .例如,在select子句中合并(l1.sku_id,l2.sku_id).

猜你在找的MsSQL相关文章