关于数据库in和exists的效率

之前一直在网上看到说数据in查询的效率不高,不会使用索引,要用exists替代。近期的项目采用分布式开发,经常会id上使用in查询,发现效率蛮高的,很明显使用了索引,这里整理下。

如下两张测试表,emp和dept。其中emp的deptno有索引为num1,和dept的deptno相关联,dept的deptno为主键。其中emp大概有500W条数据,dept有100条数据。

采用mysql测试

mysql> explain select * from emp where emp.deptno = '339558' ;

+----+-------------+-------+------+---------------+------+---------+-------+------+-------+

| id | select_type | table | type | possible_keys | key  | key_len | ref   | rows | Extra |

+----+-------------+-------+------+---------------+------+---------+-------+------+-------+

|  1 | SIMPLE      | emp   | ref  | num1          | num1 | 3       | const |   57 |       |

+----+-------------+-------+------+---------------+------+---------+-------+------+-------+

mysql> explain select * from emp where emp.deptno in('339558');

+----+-------------+-------+------+---------------+------+---------+-------+------+-------+

| id | select_type | table | type | possible_keys | key  | key_len | ref   | rows | Extra |

+----+-------------+-------+------+---------------+------+---------+-------+------+-------+

|  1 | SIMPLE      | emp   | ref  | num1          | num1 | 3       | const |   57 |       |

+----+-------------+-------+------+---------------+------+---------+-------+------+-------+

结果显示使用in和使用=与的执行计划是一样的。因此in的效率是有保障的。

mysql> explain select * from emp where emp.deptno in(select deptno from dept where dept.deptno>1000);

+----+--------------------+-------+-----------------+---------------+---------+---------+------+----------+--------------------------+

| id | select_type        | table | type            | possible_keys | key     | key_len | ref  | rows     | Extra                    |

+----+--------------------+-------+-----------------+---------------+---------+---------+------+----------+--------------------------+

|  1 | PRIMARY            | emp   | ALL             | NULL          | NULL    | NULL    | NULL | 10000000 | Using where              |

|  2 | DEPENDENT SUBQUERY | dept  | unique_subquery | PRIMARY       | PRIMARY | 4       | func |        1 | Using index; Using where |

+----+--------------------+-------+-----------------+---------------+---------+---------+------+----------+--------------------------+

但是一旦in中使用了子查询,而且是不相关子查询,我们发现外层的查询是不会使用索引的,但是内层的查询是使用索引了的。

这个时候如果把in换成exists,也不会使用索引,而且效率奇慢 select * from emp where EXISTS (select 1 from dept where dept.deptno>1000 and emp.deptno = dept.deptno) 。应该是这种写法形成了相关子查询,所以效率低。

explain select * from emp where EXISTS (select 1 from dept where dept.deptno>1000 and emp.deptno = dept.deptno);

+----+--------------------+-------+--------+---------------+---------+---------+--------------------+----------+--------------------------+

| id | select_type        | table | type   | possible_keys | key     | key_len | ref                | rows     | Extra                    |

+----+--------------------+-------+--------+---------------+---------+---------+--------------------+----------+--------------------------+

|  1 | PRIMARY            | emp   | ALL    | NULL          | NULL    | NULL    | NULL               | 10000000 | Using where              |

|  2 | DEPENDENT SUBQUERY | dept  | eq_ref | PRIMARY       | PRIMARY | 4       | testdb1.emp.deptno |        1 | Using where; Using index |

+----+--------------------+-------+--------+---------------+---------+---------+--------------------+----------+--------------------------+

下面试一下这种情况,in中的子查询为大表

select * from dept where dept.deptno in (select deptno from emp where emp.deptno<1000)

这个查询in中的数据有一万多条,但是因为内查询使用了索引,而外表的数据又很少,所以查询相当快。


综上所述:in的效率是有保证的,并不是用exists替代in就能提高查询效率的,具体要看执行计划。当使用in查询,且外表数据过的时候,最好能将两个查询拆开。这样虽然在程序中进行了两次查询,但是效率提高了很多。

如上所述第二种和第三种使用in的方式,第二个查询只需0.003秒。第三个查询却需要25秒左右




你可能感兴趣的:(关于数据库in和exists的效率)