乾貨:MySQL效能優化,in和exists
in和exists哪個效能更優
sql指令碼:
上面的sql中 訂單表中(orders) 存在user_id,而又有使用者表(users),所以我們用orders表中user_id和user表中的id 來in 和 exists。
結果
1.where後面是小表
(1)select count(1) from orders o where o.user_id in(select u.id from users u);
(2)select count(1) from orders o where exists (select 1 from users u where u.id = o.user_id);
2.where後面是大表
(1)select count(1) from users u where u.id in (select o.user_id from orders o);
(2)select count(1) from users u where exists (select 1 from orders o where o.user_id = u.id);
分析
我們用下面的這兩條語句分析:
select count(1) from orders o where o.user_id in(select u.id from users u); select count(1) from orders o where exists (select 1 from users u where u.id = o.user_id);
1.in:先查詢in後面的users表,然後再去orders中過濾,也就是先執行子查詢,結果出來後,再遍歷主查詢,遍歷主查詢是根據user_id和id相等查詢的。
即查詢users表相當於外層迴圈,主查詢就是外層迴圈
小結:in先執行子查詢,也就是in()所包含的語句。子查詢查詢出資料以後,將前面的查詢分為n次普通查詢(n表示在子查詢中返回的資料行數)
2.exists:主查詢是內層迴圈,先查詢出orders,查詢orders就是外層迴圈,然後會判斷是不是存在order_id和 users表中的id相等,相等才保留資料,查詢users表就是內層迴圈
這裡所說的外層迴圈和內層迴圈就是我們所說的巢狀迴圈,而巢狀迴圈應該遵循“外小內大”的原則,這就好比你複製很多個小檔案和複製幾個大檔案的區別
小結:如果子查詢查到資料,就返回布林值true;如果沒有,就返回布林值false。返回布林值true則將該條資料儲存下來,否則就捨棄掉。也就是說exists查詢,是查詢出一條資料就執行一次子查詢
結論
小表驅動大表。
in適合於外表大而內表小的情況,exists適合於外表小而