Oracle外连接中驱动表过滤条件在on后且为null判断导致无法使用hash join outer
Oracle外连接中驱动表过滤条件在on后且为null判断导致无法使用hash join outer
前言
偶然发现的,原因尚且不明。
实验数据库版本11.2.0.4.0。
环境构造
create table a (id number,name varchar2(20)); create table b (id number,name varchar2(20)); insert into a values(1,'a'); insert into a values(2,'b'); insert into a values(3,null); insert into a values(4,'d'); insert into a values(5,null); insert into a values(6,'a'); insert into b values(1,'a'); insert into b values(2,'b'); insert into b values(3,'c'); insert into b values(4,null); insert into b values(5,null); insert into b values(6,'a'); commit; create index idx_a_id on a(id); create index idx_a_name on a(name); create index idx_b_id on b(id); create index idx_b_name on b(name); exec dbms_stats.gather_table_stats(ownname => 'ZKM',tabname => 'A',estimate_percent => 100,method_opt => 'FOR ALL COLUMNS SIZE REPEAT',degree => 1 ,no_invalidate => false); exec dbms_stats.gather_table_stats(ownname => 'ZKM',tabname => 'B',estimate_percent => 100,method_opt => 'FOR ALL COLUMNS SIZE REPEAT',degree => 1 ,no_invalidate => false);
对照SQL组
第一组为驱动表过滤条件在on后且不是为null判断的,如下:
SQL 1 : select a.*,b.* from a left join b on a.name=b.name and a.name='a'; SQL 2 : select a.*,b.* from a left join b on a.name=b.name and a.id=1;
第二组为驱动表过滤条件在on后且为null判断的,如下:
SQL 3 : select /*+ leading(a) use_hash(a,b) */ a.*,b.* from a left join b on a.name=b.name and a.name is null; SQL 4 : select /*+ leading(a) use_hash(a,b) */ a.*,b.* from a left join b on a.name=b.name and a.name is not null; SQL 5 : select /*+ leading(a) use_hash(b) */ a.*,b.* from a left join b on a.name=b.name and a.id is not null; SQL 6 : select /*+ leading(a) use_hash(b) */ a.*,b.* from a left join b on a.name=b.name and a.id is null;
第二组为被驱动表过滤条件在on后且为null判断的,如下:
SQL 7 : select /*+ leading(a) use_hash(a,b) */ a.*,b.* from a left join b on a.name=b.name and b.name is null; SQL 8 : select /*+ leading(a) use_hash(a,b) */ a.*,b.* from a left join b on a.name=b.name and b.name is not null; SQL 9 : select /*+ leading(a) use_hash(b) */ a.*,b.* from a left join b on a.name=b.name and b.id is not null; SQL 10 : select /*+ leading(a) use_hash(b) */ a.*,b.* from a left join b on a.name=b.name and b.id is null;
说明:其中,第二组和第三组强制用hint走hash join。
实验结果汇总
以下为SQL 1-10 能否走hash join的汇总,具体实验自己可以去执行看看。
SQL 1 - 10 | SQL 1 | SQL 2 | SQL 3 | SQL 4 | SQL 5 | SQL 6 | SQL 7 | SQL 8 | SQL 9 | SQL 10 |
NL/HASH? | HASH JOIN OUTER | NESTED LOOPS OUTER | HASH JOIN OUTER |
规律总结
只有驱动表的过滤条件在on且判定类型为is [not] null的时候会导致执行计划无法选择hash join outer。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?