LEFT JOIN 到底什么时候会被优化器偷偷改写成 INNER JOIN
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
LEFT JOIN 到底什么时候会被优化器偷偷改写成 INNER JOIN写 这篇不复现业务场景,直接用最干净的两张表把这个机制的边界条件挨个测一遍:什么条件会触发这种改写、什么条件不会、条件放在不同位置结果差多少。环境还是
两张表, 数据故意设计成这样: 第一步:右表条件放 WHERE,外连接直接没了
执行计划第一行是 道理很直白: 第二步:换成 IS NULL,结果完全反过来
这次执行计划显示的是 这里有个细节容易让人愣一下:计划里写的是 为什么这次不能消除: 判断标准到这儿就很清楚了:能不能消除,看这个 WHERE 条件对外连接产生的 NULL 值判定成什么——一定是假或未知(比如普通等值比较),消除是安全的;有可能判定成真(比如 IS NULL),消除就会改变结果,优化器不会做。 第三步:条件换到左表,跟外连接消除没关系
这次执行计划是
第四步:把左表条件挪进 ON,结果比想象中多了一行
到这一步本来想验证的是:左表条件放进 ON,会不会跟"右表条件放 WHERE"一样有什么隐藏效应。
原本设想的结果是 4 行——t1 全量保留,只是 想明白这事之后觉得挺合理的: 这跟前面认为的"4 行"错在哪儿:想当然地把"左表 4 行"和"结果 4 行"划了等号,却忘了右表本来就有一对多的数据。这个坑其实挺常见,很多人写业务 SQL 的时候,只要 JOIN 的右表存在一对多关系,加不加条件、条件放哪,行数都可能跟"左表有几行"对不上,得先确认清楚右表对应关系,再看结果对不对得上。 第五步:右表条件挪进 ON,才是真正保住外连接语义的写法
这次执行计划是 对比第一步就很清楚了:同样是想找"关联到 name2='cc' 的记录",条件放 WHERE 会把 t1 里没匹配上的行连带杀掉(外连接被消除),条件放 ON 才能既过滤右表又保住左表全量。这是这篇最该记住的一条规则:对右表的过滤,只要目的是保留外连接语义,就该放 ON,不要放 WHERE。而对左表的过滤(第四步),放 ON 和放 WHERE 效果是不一样的——放 WHERE 会先筛左表再连接,放 ON 只决定"筛出来的左表行允不允许连",右表该出几行还是出几行,两者不能混着记。 第六步:Oracle |
关键字查询
相关文章
正在查询... |