查询表单是否会影响参数探查



最近,我的一位SQL开发同事遇到了这样一个问题:一个过程在所有环境中都运行良好,但在生产环境中运行良好,生产环境拥有最多的资源。参数嗅探的典型案例,但探查器指出,在整个过程中,只有一个查询需要执行很长时间:

UPDATE  a
SET     status_id = 6
FROM    usr.tpt_udef_article_grouping_buffer a
        LEFT JOIN (SELECT DISTINCT buying_domain_id, suppl_no FROM usr.buyingdomain_supplier_article) b ON  a.buying_domain_id = b.buying_domain_id
                                                                                                        AND a.suppl_no = b.suppl_no
WHERE   a.tpt_file_id = @tpt_file_id
        AND a.status_id IS NULL
        AND b.suppl_no IS NULL

由于我偏向于开发(我几乎没有管理经验),我建议重写这个查询:

  • NOT EXISTS (SELECT 1 ...) 代替LEFT JOIN (SELECT DISTINCT ...)

  • 在表usr.tpt_udef_article_grouping_buffer上设置适当的索引(SSMS建议当查询在过程之外运行时,工作量减少95%)

此外,过程中的多个查询共享相同的模式。

我知道,在程序(重新)创建后第一次运行时,参数嗅探与计划构建更相关,我认为它也受到高圈复杂度的青睐。

我的问题是:

过程中查询的编写方式(从一开始就是糟糕的执行计划)是有利于参数嗅探的出现,还是只会恶化其效果

这里唯一的参数是a.tpt_file_id = @tpt_file_id,如果这是参数嗅探,那么情况必须是这样的,即对于特定的tpt_file_id,有数千(或更多)条记录,而对于某些情况,只有很少(或没有)条记录。

在生产环境和测试环境中获得不同计划的另一个原因是机器不同。在生产环境中,您通常有更多的内存和更多的CPU/内核,这会导致优化器选择不同的计划,当然,如果表中的行数不相同,这当然会导致完全不同的计划。

您可以使用option (recompile)来检查此情况,以查看计划是否发生了更改,或者查看用于创建计划的参数值的计划缓存。它可以在平面图中最左边对象的属性中看到。

将select distinct改为exists子句可能是个好主意,当然也可以正确地为表编制索引。

最新更新