最近没啥活干,复习下基础,在 俄国一个sql在线练习网站 上作点儿sql题,常常遇到这类问题:mysql
相关联的左(l), 右(r) 表,取出左表中存在,可是右表中不存在的行(Select values present in one table but missing in another one.)sql
有一些不完整的发现,暂写成此文待补充数据库
这个问题有三种写法:oracle
1. 左链接后,选择右表中链接键为null的记录(LEFT JOIN/ IS NULL)测试
SELECT l.* FROM t_left l LEFT JOIN t_right r ON r.value = l.value WHERE r.value IS NULL
2. NOT IN网站
SELECT l.* FROM t_left l WHERE l.value NOT IN ( SELECT value FROM t_right r )
3. EXISTSspa
SELECT l.* FROM t_left l WHERE NOT EXISTS ( SELECT NULL FROM t_right r WHERE r.value = l.value )
其中第一种方法以前没怎么见过,算是新知识。 code
研究过程当中在翻到不少关于三者比较的文章,原文连接如server
SQL Serverblog
搬运一下结果总结,有兴趣的看原文
结果是否相同?
首先对于NOT EXISTS 和 LEFT JOIN/IS NULL 的结果老是彻底相同的。
若是链接字段非空,那么三者的语义在不一样数据库环境下也是彻底相同的。
当被判断字段可空的时候
Sql Server 和 ORACLE (引文中认为oracle中语义相同,但通过测试和参考AskTom 中的回答,我认为Oracle 的状况与Sql Server 一致)中, NOT IN 与另外两个的结果不不一样。
也就是说,当右表查询结果中字段值为空的时候NOT IN (NULL) 不会返回任何结果, 由于NULL与NULL并不相等。
如,当l_left 和l_right 是彻底相同的表,且全部的value全都是空的话, NOT IN返回结果数量是0,而NOT EXISTS是所有
MySQL暂未测试,待补充。预计结论同上。
效率比较?
(本部分纯搬运)
SQL Sever 中NOT IN 的效率低于NOT EXISTS和LEFT JOIN/ IS NULL,后二者的执行计划相同
MySQL对三者生成三个不一样的执行计划,其中NOT EXISTS 的效率明显低于NOT IN 和 LEFT JOIN/ IS NULL。
对于Oracle,三者生成彻底相同的执行计划,cost彻底相同。(此为原文,结论存疑)
(笔者简单测试了三种状况,结果不完整,待补充
1. 1万行作右表,主外键链接的,NOT IN 和NOT EXIST 计划一致,使用NESTED LOOPS ANTI, LEFT JOIN 使用HASH JOIN OUTER,最后一个比前边的效率略好5%
2.1 两个小于100行的表, 主外键链接, LEFT JOIN和NOT EXISTS 计划相同,使用HASH JOIN RIGHT ANTI ,NOT IN 使用FITER, 后者效率差22%
2.2 同上两个小表,可空字段链接,状况彻底同2.1 )