前言
在面试谈到sql优化的一些经验时,有些面试者会回答:写sql时,最好用exists来代替in,因为in不走索引,所以用exists的sql性能较好,那真的是这样么?
以下用AB两表,做个示例,两表都有一个id字段,而两个表都为id字段建立了索引
In
in的作用其实就是把范围内存在的数据做个返回,先看看下图的简单示例sql:
select * from A where id in (select id from B)
这句sql等价于两个循环:
for select id from B
for select * from A where A.id = B.id
其实就是对B表的id做个外层循环,而内层再嵌套一层A表的id循环,内层循环里判断A表和B表的id是否相等,相等的话就是要返回的数据。
Exists
exists的作用就是把主查询的数据,放到自查询中做条件的验证,结果是true则保留主查询中的结果,为false则不保留,以下用exists实现和in一样的效果:
select * from A where exists(select * from B where B.id = A.id)
这句sql也等价于两个循环:
for select * from A
for select * from B where B.id = A.id
其实就是对A表的id做个外层循环,而内层再嵌套一层B表的id循环,内层循环里判断B表和A表的id是否相等,相等的话就是要返回的数据。
这时引申出一个sql优化的规则:以小表驱动大表,mysql连接数会更少,sql性能会更佳
分析下,用in时,是in里面的表驱动外面的表,所以如果B表相对于A表是小表,用in比较好。而用exists时,是外面的表驱动exists里面的表,所以如果A表相对于B表是小表,则用exists比较好。
总结
明白了IN 和EXISTS 的原理后,配合上小表驱动大表的优化规则,可以得出用EXISTS 或者是用IN ,还需要根据表中数据情况而定。
IN 适合于外表大而内表小的情况,而EXISTS 适合于外表小而内表大的情况。
况且大多数时候是没法用EXISTS 来替换IN 的,比如如下语句
select * from user where id in(1,2,3)
这句语句有没有多表连接,就不适合用EXISTS ,而且坊间盛传的IN 不走索引,其实也是不对的,详情见: 不要再问我 in,exists 走不走索引了。
|