这篇文章放在草稿箱里面很长时间了,直到最近又看到了这篇多个公号转发过的神文:《公司新来一个技术总监:谁再在 SQL 中写 in 和 not in,直接走人!》.
下面有几个说法, 分别来自两本SQL入门经典书, 我认为不太妥当:
1-1.关于子查询用exists还是in的问题, 书上说exists比in写法效率高:
作者给出的例子:
作者对上述结论做了解释:
老虎刘点评:
这本书是2017年出版的中译本,原书是哪一年出版我不太清楚.最后一句话我还是比较认可的.
oracle数据库从9i开始就支持自动查询转换, 常规写法的 in和exists, 经过优化器的查询转换后,执行计划是一样的. 有几种特殊情况, in写法的效率反而要高于exists,从另一个角度说明优化器还是考虑得不够周到.
至于not in和not exists两种写法,如果关联字段都有not null约束, 也是一样的, 但是很多时候没有这个not null的约束或条件,二者在逻辑上就不是等价的. 大部分情况还是建议使用not exists. 我在之前的文章有说明,文章链接 : 102-not in和not exists到底选哪个?这个问题有点复杂,但是结论很简单,不要被专家们带偏了。
其他数据库,比如mysql,从8.0版本开始支持in/exists的自动转换; postgresql 多年前的版本也已经支持in/exists的自动转换了. 可能也有特殊情况, 特殊对待即可.
1-2. 使用非等值自关联, 计算产品价格排名情况:
老虎刘点评:
如果一个只有几万条记录的表,用这种非等值关联的写法, 消耗的资源和时间都是很大的(类似笛卡尔集). 书上用这种写法只考虑了功能的实现, 完全没有考虑性能. 也有可能是当时使用的数据库不支持分析函数(常见数据库, 较晚支持分析函数的应该只有mysql了).
以上内容来自2017年11月出版的的:
(基于oracle 10g, SQL server 2005, DB2 9.1 , PG 9.6 , Mysql 5.0)
再看另一本书的内容:
2-1 用标量子查询写法计算每个客户订单数:
老虎刘点评:
很多开发人员喜欢使用这种标量子查询的写法, 这种写法写起来非常顺手,但是很多时候会影响SQL的执行效率.改成外关联一般是比较好的选择.
2-2 使用union做 or 的改写:
老虎刘点评:
逻辑上不等价,还增加了去重的额外操作,影响性能. 正确的改写方法应该用union all, 比如union all的上半部分增加 and( cust_name 'Fun4All' or cust_name is null)
以上内容来自2020年出版的第5版:
上面提到的两本书, 重点讲述功能的实现,作为SQL入门是一个不错的选择.但是如果要从中学习性能优化相关内容,就不太适合了.