SQL Server 2017+ 的自适应联接是优化器在批处理模式下自动启用的特性,依赖列存储索引或显式启用批次模式,需开启数据库级自适应配置、兼容级别≥140,并避免破坏基数估算的写法,实际生效须通过执行计划中Adaptive="true"及运行后ActualJoinType确认。

SQL Server 2017+ 的自适应连接(Adaptive Join)不是你手动写的语法,而是查询执行时由优化器自动启用的特性——你没法在 SELECT 里写 ADAPTIVE JOIN,但能通过配置和写法影响它是否生效。
自适应连接只在批处理模式下触发
SQL Server 的 Adaptive Join 当前(截至 2026 年)仅支持批处理执行模式(batch mode),这意味着它依赖于列存储索引(Columnstore Index)或启用了批次模式的行存储(如通过 QUERYTRACEON 1118 或 SQL Server 2022+ 的行存储批次模式)。纯行存储 + 行模式执行(row mode)下,即使开了自适应查询处理(ALTER DATABASE SCOPED CONFIGURATION SET DISABLE_OPTIMIZER_ROWGOAL = OFF),也不会出现自适应连接算子。
- 检查执行计划中是否出现
Adaptive Join算子:右键查看属性,看Adaptive是否为True,且Actual Join Type在运行后才确定为Hash Join或Nested Loops Join - 若表无列存储索引,又没显式用
OPTION (USE HINT('ENABLE_BATCH_MODE'))(SQL Server 2019+),基本不会触发 - CTE、视图、多语句 TVF 中的连接可能被隔离优化,导致自适应逻辑无法跨作用域生效
必须开启数据库级自适应查询处理开关
即使满足批处理条件,Adaptive Join 默认仍可能被禁用。需确认以下配置已启用:
- 执行
SELECT * FROM sys.database_scoped_configurations WHERE name = 'DISABLE_OPTIMIZER_ROWGOAL',值应为OFF(注意:这个配置名有误导性,实际控制自适应能力) - 更直接的方式是运行:
ALTER DATABASE SCOPED CONFIGURATION SET AUTOMATIC_TUNING (FORCE_LAST_GOOD_PLAN = OFF)不影响它,但确保没全局禁用自适应;真正关键的是:ALTER DATABASE SCOPED CONFIGURATION SET PARAMETER_SNIFFING = ON—— 参数嗅探关闭会导致基数估算失真,间接让自适应决策失效 - 如果用的是 Azure SQL 数据库,该功能默认开启;本地 SQL Server 2017+ 需确保兼容级别 ≥ 140(即
COMPATIBILITY_LEVEL = 140或更高)
写法上要避免破坏基数估算的常见陷阱
自适应连接依赖优化器对“左侧输入行数”的准确预估来决定何时切分路径。一旦估算严重偏差,它可能退化为固定策略,甚至不生成自适应节点。
- 避免在
JOIN条件或WHERE中对连接字段使用函数,例如:ON UPPER(t1.code) = t2.code或WHERE t1.created_date >= DATEADD(day, -7, GETDATE())—— 这会让统计信息失效 - 不要用局部变量代替参数:用
DECLARE @dt DATE = '2026-04-01'; SELECT ... WHERE date_col > @dt会触发“乐观估算”(通常按 30% 猜),而用sp_executesql传参才能复用正确统计 - 小表驱动大表时,若小表结果集不稳定(如带
TOP或OFFSET-FETCH),自适应连接可能因预估行数=1而始终选 Nested Loops,哪怕实际返回 10 万行
如何验证它真的起了作用
不能只看执行计划图形界面里的“Adaptive Join”字样——那只是编译期声明。真正起效要看运行后的实际行为:
- 执行查询后,用
SELECT * FROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp WHERE qs.last_execution_time > DATEADD(mi, -5, GETDATE())找到刚跑的 plan,再用 XML 查看及其子节点中的ActualJoinType - 对比两次相同查询(一次加
OPTION (RECOMPILE),一次不加):前者能反映真实数据分布,后者可能复用旧计划并跳过自适应重决策 - 最简验证方式:建一张小表(10 万行),做
INNER JOIN,强制走列存储(比如大表建CLUSTERED COLUMNSTORE INDEX),然后在 SSMS 中看“实际执行计划”里该算子下方是否动态显示了两种连接类型的分支及实际选择路径
自适应连接的价值不在语法炫技,而在应对不可预测的数据倾斜——但它高度依赖底层统计质量、执行模式和查询结构。一旦漏掉列存储、关了参数嗅探、或者写了带函数的 ON 条件,它就退化成普通连接,连提示都不给你留一个。










