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_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). (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |