我们使用一些“聚合”视图使用鉴别器从多个表中进行选择(注意:这些视图不是分区视图,因为鉴别器不在基表中)。这通常在使用 时效果很好option(recompile)
,因为查询计划程序将在选择查询计划之前消除不可到达的union all
路径。
但是,当将结果选择为标量变量时,这种恒定折叠优化似乎失败了。将结果选择到临时表变量中不会对重新编译进行反优化。
这是 SQL Server 2017 中的复制案例:
-- A table, don't need any data.
create table [test].test_table (col1 int, primary key (col1));
-- A simple 'aggregate' view. Using the same table here is irrelevant and,
-- while the view shows the scenario, it might not be required to reproduce the issue.
create view [test].test_view as
select col1, descrim = 1 from [test].test_table
union all
select col1, descrim = 2 from [test].test_table
正常查询,这会导致优化的查询计划仅涉及其中一个union all
分支:
declare @descrim int = 2;
select count(col1)
from [test].test_view
where descrim = @descrim
option (recompile) -- explicit recompile here "works"
但是,一旦使用“选择到标量变量”,该计划就会变得不优化,因为它不会消除未使用的联合。(在查询文本中使用文字值时,该计划仍然正确优化。)
declare @descrim int = 2;
declare @brokeit int;
select @brokeit = count(col1)
from [test].test_view
where descrim = @descrim
option (recompile) -- explicit recompile here does NOT optimize plan for @descrim!
1. 这种去优化是“预期的”吗?
2. 关于和/或选择标量变量的这种显着的去优化行为在哪里option(recompile)
记录或以其他方式深入讨论?
3. 有没有一种简单的方法可以在select @x = ..
不使用临时表(变量)的情况下获得重新编译优化的计划?
虽然在查询执行期间,这union all
将阻止对辅助工件的实际 IO 访问,但这仍然是查询计划生成的问题。在产生此问题的特定错误情况下,保留多个表以供考虑会阻止 SQL Server 选择适当的搜索计划,并且生成的计划选项在给定域中是非常糟糕的选择。
第一个“好”计划:
第二个也是“坏”的计划:
这个“坏”计划也有一个隐式转换警告,让我怀疑选择到标量变量可能会绕过许多不同的优化 - 甚至option(recompile)
完全忽略提示。