硬编码DOCUMENT_TYPE筛选条件查询缓慢、使用变量则快速的原因及无变量优化方案咨询
这事儿我遇过好几次,核心问题大概率出在SQL Server查询优化器的执行计划选择差异上,具体来说可能是这几个原因:
1. 统计信息过时或不准确
当你用硬编码值2的时候,查询优化器会去查DOCUMENT_TYPE列的统计信息,估算这个值对应的行数。如果统计信息很久没更新,或者这个值的实际数据分布和统计信息里的偏差很大(比如2这个值其实占比极低,但统计信息显示它占了很大比例),优化器可能会选择一个低效的执行计划——比如放弃索引走全表扫描,自然就慢了。
而用变量@a的时候,优化器没法直接拿到具体值,会用默认的选择性估计(比如对于int类型列,默认认为这个值会匹配10%左右的行),反而选了更合适的索引或者执行策略,所以速度快很多。
2. 视图的执行计划展开问题
你的查询是基于视图VW_PERFORMANCE_TEST的,硬编码筛选时,优化器可能没有正确展开视图的逻辑,没法把筛选条件下推到底层表,导致扫描了更多的数据;而用变量的时候,优化器反而能更好地做条件下推,直接在底层表上应用筛选,性能自然上去了。
不用变量怎么实现同等性能?
这里给你几个可行的方案,不用变量也能让硬编码的查询跑起来飞快:
方案1:更新统计信息
先把视图底层表的统计信息更新一下,让优化器拿到准确的数据分布:
-- 更新视图本身的统计信息 UPDATE STATISTICS dbo.VW_PERFORMANCE_TEST WITH FULLSCAN; -- 如果视图依赖多个表,最好也更新底层表的统计信息 UPDATE STATISTICS dbo.底层表1 WITH FULLSCAN; UPDATE STATISTICS dbo.底层表2 WITH FULLSCAN;
更新完之后再跑硬编码的查询,大概率会和变量版速度一致。
方案2:用查询提示强制优化器选择高效执行计划
如果更新统计信息没用,你可以指定让查询用某个高效的索引(前提是你知道哪个索引适合PERIOD_ID + DOCUMENT_TYPE的筛选):
SELECT [GroupBy1].[A1] AS [C1] FROM ( SELECT COUNT(1) AS [A1] FROM [dbo].[VW_PERFORMANCE_TEST] AS [Extent1] WITH (INDEX(IX_PERIOD_DOC_TYPE)) -- 替换成你的实际索引名 WHERE (13 = [Extent1].[PERIOD_ID]) AND (2 = [Extent1].[DOCUMENT_TYPE]) ) AS [GroupBy1]
或者用OPTION (OPTIMIZE FOR UNKNOWN),让优化器用和变量版一样的默认选择性估计:
SELECT [GroupBy1].[A1] AS [C1] FROM ( SELECT COUNT(1) AS [A1] FROM [dbo].[VW_PERFORMANCE_TEST] AS [Extent1] WHERE (13 = [Extent1].[PERIOD_ID]) AND (2 = [Extent1].[DOCUMENT_TYPE]) ) AS [GroupBy1] OPTION (OPTIMIZE FOR UNKNOWN);
方案3:手动展开视图逻辑
如果视图本身比较复杂,优化器没法很好地处理,你可以把视图的SQL直接写到查询里,手动把筛选条件下推到底层表,这样优化器能更精准地生成执行计划。比如原来的视图是几个表的关联,你直接写关联逻辑,然后在每个表上尽可能早地应用PERIOD_ID和DOCUMENT_TYPE的筛选。
内容的提问来源于stack exchange,提问作者Javid

