1. 程式人生 > >mysql中exit和in的區別

mysql中exit和in的區別

原文地址:https://segmentfault.com/a/1190000008709410

提前準備

為了大家學習方便,北哥在這裡面建立兩張表併為其新增一些資料

一張會員表,一張會員下單表。

會員表資料

id user email
1 abei [email protected]
2 wh [email protected]
3 liuhuan [email protected]

訂單表

id user_id create_time ...
1 1 1489579802 ...
2 2 1489579802 ...
3 1 1489579802 ...
4 3 1489579802 ...
5 2 1489579802 ...
6 1 1489579802 ...

我們將用這兩張表做演示。

什麼是exists

exists表示存在,它常常和子查詢配合使用,例如下面的SQL語句

SELECT * FROM `user` 
    WHERE exists (SELECT * FROM `order` WHERE user.id = order.user_id)

exists用於檢查子查詢是否至少會返回一行資料,該子查詢實際上並不返回任何資料,而是返回值TrueFalse

當子查詢返回為真時,則外層查詢語句將進行查詢。
當子查詢返回為假時,外層查詢語句將不進行查詢或者查詢不出任何記錄。

因此上面的SQL語句旨在搜尋出所有下過單的會員

。需要注意的是,當我們的子查詢為 SELECT NULL 時,MYSQL仍然認為它是True

exists和in的區別和使用場景

是的,其實上面的例子,in這貨也能完成,如下面SQL語句

SELECT * FROM `user`  
    WHERE id in (SELECT user_id FROM `order`)

那麼!in和exists到底有啥區別那,要什麼時候用in,什麼時候用exists那?接下來阿北一一教你。

我們先記住口訣再說細節!“外層查詢表小於子查詢表,則用exists,外層查詢表大於子查詢表,則用in,如果外層和子查詢表差不多,則愛用哪個用哪個。”

In關鍵字原理

SELECT * FROM `user`  
    WHERE id in (SELECT user_id FROM `order`)

in()語句只會執行一次,它查出order表中的所有user_id欄位並且快取起來,之後,檢查user表的id是否和order表中的user_id相當,如果相等則加入結果期,直到遍歷完user的所有記錄。

in的查詢過程類似於以下過程

$result = [];
$users = "SELECT * FROM `user`";
$orders = "SELECT user_id FROM `order`";
for($i = 0;$i < $users.length;$i++){
    for($j = 0;$j < $orders.length;$j++){
        // 此過程為記憶體操作,不涉及資料庫查詢。
        if($users[$i].id == $orders[$j].user_id){
            $result[] = $users[$i];
            break;
        }
    }
}

我想你已經看出來了,當order表資料很大的時候不適合用in,因為它最多會將order表資料全部遍歷一次。

如:user表有10000條記錄,order表有1000000條記錄,那麼最多有可能遍歷10000*1000000次,效率很差.

再如:user表有10000條記錄,order表有100條記錄,那麼最多有可能遍歷10000*100次,遍歷次數大大減少,效率大大提升.

exists關鍵字原理

SELECT * FROM `user` 
    WHERE exists (SELECT * FROM `order` WHERE user.id = order.user_id)

在這裡,exists語句會執行user.length次,它並不會去快取exists的結果集,因為這個結果集並不重要,你只需要返回真假即可。

exists的查詢過程類似於以下過程

$result = [];
$users = "SELECT * FROM `user`";
for($i=0;$i<$users.length;$i++){
    if(exists($users[$i].id)){// 執行SELECT * FROM `order` WHERE user.id = order.user_id
        $result[] = $users[$i];
    }
}

你看到了吧,當order表比user表大很多的時候,使用exists是再恰當不過了,它沒有那麼多遍歷操作,只需要再執行一次查詢就行。

如:user表有10000條記錄,order表有1000000條記錄,那麼exists()會執行10000次去判斷user表中的id是否與order表中的user_id相等.

如:user表有10000條記錄,order表有100000000條記錄,那麼exists()還是執行10000次,因為它只執行user.length次,可見B表資料越多,越適合exists()發揮效果.

但是:user表有10000條記錄,order表有100條記錄,那麼exists()還是執行10000次,還不如使用in()遍歷10000*100次,因為in()是在記憶體裡遍歷,而exists()需要查詢資料庫,我們都知道查詢資料庫所消耗的效能更高,而記憶體比較很快.

因此我們只需要記住口訣:“外層查詢表小於子查詢表,則用exists,外層查詢表大於子查詢表,則用in,如果外層和子查詢表差不多,則愛用哪個用哪個。”