sql server 2022的自适应join是在执行时动态选择nested loop或hash join的机制,依赖批处理模式、兼容级别≥150、准确基数估算及启用数据库级自适应配置,执行计划中显示adaptive="true"且actualjointype可验证实际选用算法。

SQL Server 2022 的自适应 JOIN 是什么,它真能自动优化?
不是“自动变快”,而是运行时动态选 JOIN 算法。SQL Server 2022 在编译阶段生成一个带“自适应联接运算符”的执行计划,但不立即决定用 Nested Loop、Hash Join 还是 Merge Join;而是在实际执行到该节点时,根据已处理行数、内存压力、统计信息新鲜度等实时反馈,现场切换最合适的算法。
这个机制只对 INNER JOIN 和 LEFT OUTER JOIN 生效,RIGHT OUTER JOIN 和 FULL OUTER JOIN 不支持。它也不是万能开关——若驱动表预估行数严重失真(比如统计信息过期超 7 天),自适应逻辑可能选错分支,反而比固定计划更慢。
什么时候会触发自适应 JOIN,怎么看执行计划?
满足三个条件才会启用:
- 查询中至少有一个
JOIN操作,且连接字段有索引或统计信息 - 优化器预估驱动表输出行数在 100~100,000 行之间(太小或太大都跳过)
- 数据库兼容级别 ≥ 150(即 SQL Server 2019+),且未显式禁用:
ALTER DATABASE SCOPED CONFIGURATION SET DISABLE_BATCH_MODE_ON_ROWSTORE = OFF
在图形执行计划中找带黄色闪电图标的 Adaptive Join 运算符;鼠标悬停能看到 “Actual Join Type” 字段,显示最终选的是 Nested Loop 还是 Hash Join。如果看到 “Adaptive Threshold Rows” 值为 8421,说明当左表已输出 ≤ 8421 行时走 Nested Loop,否则切 Hash Join。
为什么开了自适应 JOIN,查询反而更慢了?
常见原因不是功能失效,而是环境没配好:
- 统计信息陈旧:执行
UPDATE STATISTICS或sp_updatestats,尤其对驱动表的连接列和 WHERE 条件列 - 内存不足:自适应逻辑需要额外工作内存,若
max server memory设置过低,会导致频繁 spill 到 tempdb,拖慢 Hash 分支 - 大文本字段参与 JOIN:哪怕只是
ON t1.id = t2.ref_id,但如果t2表含NVARCHAR(MAX)列且被选为构建侧(build side),仍会触发 LOB 加载开销——此时应先用 CTE 剥离大字段再 JOIN - 强制重编译干扰:语句里写了
OPTION (RECOMPILE),每次执行都重新生成计划,自适应阈值无法复用历史反馈
手动干预自适应行为的实用方法
不建议全局关掉,但可针对单条语句微调:
- 想锁定用 Hash Join:加提示
OPTION (HASH JOIN),绕过自适应判断 - 想避免 Hash 分支(比如小结果集怕 spill):加
OPTION (LOOP JOIN),但需确保连接列有索引,否则 Nested Loop 可能全表扫描 - 临时禁用自适应(调试用):
ALTER DATABASE SCOPED CONFIGURATION SET BATCH_MODE_ON_ROWSTORE = OFF,之后再DBCC FREEPROCCACHE清空计划缓存 - 检查是否生效:运行后查
sys.dm_exec_query_stats,看adaptive_plan = 1且last_execution_time匹配你的查询时间
真正关键的不是“开没开自适应”,而是驱动表行数预估是否靠谱——这取决于统计信息质量、WHERE 条件选择性、以及有没有隐式转换污染索引使用。其他所有优化,都是在这基础上起作用的。










