自适应JOIN在SQL Server 2019中起作用——但必须同时满足三个硬性条件:兼容级别为150、执行计划启用批处理模式、内侧实际行数与估算偏差超2倍且总行数>10000。

自适应JOIN在SQL Server 2019中到底起不起作用?
不起作用——除非你同时满足三个硬性条件:COMPATIBILITY_LEVEL = 150、执行计划走BATCH MODE、内侧(子查询或右表)实际行数与估算偏差超过2倍且总行数>10000。缺一不可。很多团队开了150级别却没效果,根本原因是没触发批处理模式,或者压根没跑出足够大的数据量。
为什么INNER JOIN和LEFT JOIN都可能触发自适应?
自适应JOIN不看语法类型,只看执行计划里是否出现Adaptive Join算子。它最常出现在APPLY改写后的场景(比如CROSS APPLY (SELECT ...)),因为这类结构天然倾向生成Nested Loops,而自适应机制正是为“预估严重失准的嵌套循环”准备的。但如果你用的是标准INNER JOIN,只要优化器判断内表估算偏差大+满足批处理条件,同样会插入自适应分支。
- INNER JOIN → 可能转为
Hash Join避免逐行扫描 - LEFT JOIN → 若右表返回大量NULL,也可能触发切换(但概率低于APPLY)
- RIGHT JOIN / FULL JOIN → 不支持自适应,直接跳过
怎么确认你的查询真正在用自适应JOIN?
不能只看执行计划图标,要查sys.dm_exec_query_plan或导出XML,搜索<relop logicalop="Adaptive Join">。更直接的方法是打开实际执行计划(<code>SET STATISTICS XML ON),在算子属性里找Adaptive字段是否为True,以及IsAdaptive是否为1。
- 没看到
Adaptive Join节点?先检查兼容级别:SELECT compatibility_level FROM sys.databases WHERE name = DB_NAME() - 看到节点但没切换?说明运行时内侧行数没超阈值,或批处理未激活(比如没列存储索引,也没开
trace flag 11256) - 用了
OPTION (RECOMPILE)却失效?因为自适应依赖运行时统计,而强制重编译会跳过部分反馈路径
最容易被忽略的部署细节
改完COMPATIBILITY_LEVEL后,旧执行计划不会自动失效。哪怕你重启SQL Server服务,缓存里的计划依然按老规则跑。必须手动清空:DBCC FREEPROCCACHE,否则永远看不到自适应生效。
- 清缓存影响大?可定向清理:
DBCC FREEPROCCACHE(dbid)或用sys.dm_exec_cached_plans定位具体plan_handle - 想长期监控哪些查询触发了自适应?建扩展事件会话,捕获
adaptive_join_skipped和adaptive_join_consumed事件 - 列存储不是必需项,但
trace flag 11256仅对Azure SQL或企业版有效,标准版只能靠列存储索引驱动批处理

















