MySQL中IN太慢怎么优化


1. IN在MySQL中是先查询子查询的表,然后将内表与外表进行一个笛卡尔积,再按条件进行筛选,在内表数据相对较小时,IN的速度较快

2.用IN效率低的原因

  • 跟实际的关联数据类型
  • 列的索引
  • 表数据大小
  • 等等情况

3.使用EXISTS来替代IN

  • EXISTS是先将外表作为驱动表,每次都是去查询外表数据,然后再进行判断,如果成立就将结果保留,否则则删除该行

  • 与IN的区别就在于:如果子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用in, 反之如果外层的主查询记录较少,子查询中的表大,又有索引时使用exists。

  • 驱动顺序的不同:IN先执行子查询,EXISTS以外层为驱动表,先被访问

  • 逻辑:IN是以外表和内表进行连接,EXISTS是对外表的循环

  • 使用 not in 和 not exists

    • not in会造成子查询的全表扫描,没使用到索引,而not exists的子查询仍然能用上索引,理论上无论内表大还是外表大,not exists都会效率更高,但实际上不一定
  • 案例:

  • --users表有1000条记录,id自增,id都大于0
    
    select * from users where exists (select * from users limit 0); --输出多少条记录?
    select * from users where exists (select * from users where id < 0); --输出多少条记录?
    
    答案(请选中查看):
    10000条
    0条
    原因:exists查询的本质,只要碰到有记录,则返回true;所以limit根本就不会去管,或者说执行不到
    
  • exists可以完全代替in吗?
    不能。
    
    例如:
    -没有关联字段的情况:枚举常量
    select * from areas where id in (4, 5, 6);
    
    -没有关联字段的情况:这样exists对子查询,要么全true,要么全false
    select * from areas where id in (select city_id from deals where deals.name = 'xxx'); 
    
  • 在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接。 
    在这种情况下,使用exists(或not exists)通常将提高查询的效率。 
    举例: 
    (低效) 
    select ... from table1 t1 where t1.id > 10 and pno in (select no from table2 where name like 'www%'); 
    (高效) 
    select ... from table1 t1 where t1.id > 10 and exists (select 1 from table2 t2 where t1.pno = t2.no and name like 'www%'); 
    
  • 用exists替换distinct: 
    当提交一个包含一对多表信息的查询时,避免在select子句中使用distinct. 一般可以考虑用exists替换 
    举例: 
    (低效) 
    select distinct d.dept_no, d.dept_name from t_dept d, t_emp e where d.dept_no = e.dept_no; 
    (高效) 
    select d.dept_no, d.dept_name from t_dept d where exists (select 1 from t_emp where d.dept_no = e.dept_no); 
    exists使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果. 
    
  • 用表连接替换exists: 
    通常来说,采用表连接的方式比exists更有效率。 
    举例: 
    (低效) 
    select ename from emp e where exists (select 1 from dept where dept_no = e.dept_no and dept_cat = 'W'); 
    SELECT ENAME 
    (高效) 
    select ename from dept d, emp e where e.dept_no = d.dept_no and dept_cat = 'W';
    

4.使用连接查询


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM