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