既然这个问题不断得到意见,我会在这里总结一下,所以新人不必忍受历史:
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).