我正在尝试理解这种行为。我的下面的陈述需要将近半个小时才能完成。但是,当我用值1替换参数@IsGazEnabled(在底部的where子句的case语句中)时,它只需要一秒钟。
查看估计的执行计划,当使用参数时需要30分钟时,大部分成本(92%)都是嵌套循环(左反半连接)。似乎还有一些并行性正在发生。我只是在学习执行计划,我有点困惑。与不使用参数时生成的计划非常不同。
那么如果将参数与没有参数进行比较,如何对执行计划和性能产生如此大的影响呢?
declare @IsGazEnabled tinyint;
set @IsGazEnabled = 1;
select 'CT Ref: ' + accountreference + ' - Not synced due to missing property ref ' + t.PropertyReference
from CTaxAccountTemp t
where not exists (
select *
from ccaddress a
left join w2addresscrossref x on x.UPRN = a.UPRN
and x.appcode in (
select w2source
from GazSourceConfig
where GazSource in (
select GazSource
from GazSourceConfig
where W2Source = 'CTAX'
)
union all select 'URB'
)
where t.PropertyReference = case @IsGazEnabled when 1 then x.PropertyReference else a.PropertyReference end
);
答案 0 :(得分:2)
这可能是因为SQL Server(查询优化器)在创建初始执行计划时使用了提供的参数的值。如果某些表中的值不均匀分布,则创建的计划可能对参数的某些值非常有效,但对其他值则非常差。这通常称为参数嗅探。您可以使用查询提示(OPTIMIZE FOR X)或在每次运行之前重新编译存储过程(WITH RECOMPILE)来解决此问题。在实施之前,您应该仔细阅读这些选项,因为它们都有副作用。
答案 1 :(得分:1)
我认为你应该重新考虑这个问题。尝试并避免使用NOT EXISTS()
作为初学者 - 因为这通常非常低效(在这些情况下我通常更喜欢LEFT JOIN
- 并且相应的WHERE x IS NULL
- x是右侧的东西)
虽然你可能是基于CASE的WHERE,但是现在导致内部查询被评估为每一行!我认为你最好加入两组取消资格的标准,但在参赛条件中加入参数 - 然后检查左边两个连接标准的右侧是否有任何内容
以下我认为可以改写:
declare @IsGazEnabled tinyint;
set @IsGazEnabled = 1;
select 'CT Ref: ' + accountreference + ' - Not synced due to missing property ref ' + t.PropertyReference
from CTaxAccountTemp t
left join ccaddress a2 ON t.PropertyReference = a2.PropertyReference and @IsGazEnabled = 0
left join
(
ccaddress a
join w2addresscrossref x on x.UPRN = a.UPRN
and x.appcode in ( -- could make this a join for efficiency....
select w2source
from GazSourceConfig
where GazSource in (
select GazSource
from GazSourceConfig
where W2Source = 'CTAX'
)
union all select 'URB'
)
) ON t.PropertyReference = x.PropertyReference AND and @IsGazEnabled = 1
WHERE
a2.PropertyReference IS NULL
AND x.PropertyReference IS NULL
;