WHERE 子句中的优化似乎不适用于 UNION
Posted
技术标签:
【中文标题】WHERE 子句中的优化似乎不适用于 UNION【英文标题】:Optimization in WHERE clause seems to be not working with UNION 【发布时间】:2020-10-30 15:30:37 【问题描述】:我尝试了以下格式的 SQL 脚本。 (有多个连接可生成 set1、set2 和 set3,但为简单起见将其删除)。
SELECT * FROM (
SELECT * FROM Set1
WHERE someConditions
UNION
SELECT * FROM Set2
WHERE someConditions
UNION
SELECT * FROM Set3
WHERE @include = 1 AND otherConditions..
) as t
ORDER BY ...
人们会期望当@include = 0
时,最后一个UNION
的整体将被忽略。这也是我在查找有条件地执行UNION
时看到的。
但对我来说不是这样;即使@include = 0
,查询也需要很长时间才能执行。如果我注释掉最后一部分,查询将执行得更快。
SELECT * FROM (
SELECT * FROM Set1
WHERE someConditions
UNION
SELECT * FROM Set2
WHERE someConditions
--UNION
--SELECT * FROM Set3
--WHERE @include = 1 AND otherConditions..
) as t
ORDER BY ...
为什么编译器无法识别它?有没有办法在这种情况下优化查询?
【问题讨论】:
也许试试option (recompile)
?
或者使用动态 SQL 并创建一个只包含您需要的部分的查询。另外,您真的需要UNION
,还是UNION ALL
仍然会产生正确的结果? UNION
是一个成本更高的运算符,只有在您确实需要时才应使用它。
只是一种预感,但您可以尝试用“Union All”替换所有“Union”,然后将外部“select”转换为“select distinct”。查询引擎可能更有可能以这种方式分别处理三个查询组件。
option (recompile)
和 UNION ALL
对我没有任何影响。可能不得不使用动态 SQL 作为最后的手段。
@eshirvana 不;最后为整个查询添加。我们不能为内部查询添加recompile
,可以吗?这会导致语法错误。
【参考方案1】:
对我来说,OPTION(RECOMPILE) 在类似的测试设置上运行良好 - 在没有提示的情况下重用糟糕的计划(假设之前使用 @include = 1 运行),但在使用 RECOMPILE 时创建一个新的、更好的计划。
如果这对您不起作用,您可以尝试使用 IF 拆分成两个不同的语句,例如:
BEGIN
IF @include = 1
BEGIN
SELECT * FROM Set1
WHERE someConditions
UNION
SELECT * FROM Set2
WHERE someConditions
UNION
SELECT * FROM Set3
WHERE otherConditions..
END
ELSE
BEGIN
SELECT * FROM Set1
WHERE someConditions
UNION
SELECT * FROM Set2
WHERE someConditions
END
END
【讨论】:
出于某种原因,重新编译对我没有帮助。但我喜欢这种拆分的想法,即使它可能不利于维护。以上是关于WHERE 子句中的优化似乎不适用于 UNION的主要内容,如果未能解决你的问题,请参考以下文章
ADD_DATE() 不适用于 mysql 中的 where 子句
Laravel UNION ALL 不适用于 where 语句