向where子句添加参数时的性能

时间:2014-12-18 15:25:46

标签: sql sql-server tsql sql-execution-plan sqlperformance

我正在尝试理解这种行为。我的下面的陈述需要将近半个小时才能完成。但是,当我用值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
        );

2 个答案:

答案 0 :(得分:2)

这可能是因为SQL Server(查询优化器)在创建初始执行计划时使用了提供的参数的值。如果某些表中的值不均匀分布,则创建的计划可能对参数的某些值非常有效,但对其他值则非常差。这通常称为参数嗅探。您可以使用查询提示(OPTIMIZE FOR X)或在每次运行之前重新编译存储过程(WITH RECOMPILE)来解决此问题。在实施之前,您应该仔细阅读这些选项,因为它们都有副作用。

有关详细信息,请参阅Brent Ozar网站上的几篇文章herehere

答案 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      
    ;