咱們在學習Yii2的時候,必定接觸過這樣的where輸入php
$query->where(["exists",xxxx]); User::find()->where(["exists",xxxx])->all();
是的,這是MYSQL的exists關鍵詞,今天咱們就來講說這個exist,爲了給你們更清楚的講解,先給你們說下本文目錄:sql
什麼是exists數據庫
exists和in的區別和使用場景緩存
使用Yii2的Query Builder實現一個exists語句性能
要本身看哈。學習
爲了你們學習方便,北哥在這裏面創建兩張表併爲其添加一些數據ui
一張會員表,一張會員下單表。spa
會員表數據code
id | user | |
---|---|---|
1 | abei | abei@nai8.me |
2 | wh | abei@maige123.com |
3 | liuhuan | 267765@qq.com |
訂單表圖片
id | user_id | create_time | ... |
---|---|---|---|
1 | 1 | 1489579802 | ... |
2 | 2 | 1489579802 | ... |
3 | 1 | 1489579802 | ... |
4 | 3 | 1489579802 | ... |
5 | 2 | 1489579802 | ... |
6 | 1 | 1489579802 | ... |
咱們將用這兩張表作演示。
exists表示存在,它經常和子查詢配合使用,例以下面的SQL語句
SELECT * FROM `user` WHERE exists (SELECT * FROM `order` WHERE user.id = order.user_id)
exists用於檢查子查詢是否至少會返回一行數據,該子查詢實際上並不返回任何數據,而是返回值True或False。
當子查詢返回爲真時,則外層查詢語句將進行查詢。
當子查詢返回爲假時,外層查詢語句將不進行查詢或者查詢不出任何記錄。
所以上面的SQL語句旨在搜索出全部下過單的會員。須要注意的是,當咱們的子查詢爲 SELECT NULL 時,MYSQL仍然認爲它是True。
是的,其實上面的例子,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,若是外層和子查詢表差很少,則愛用哪一個用哪一個。」
我想我只須要寫一個Query Builder的用法,其餘你應該能觸類旁通了吧
$query = new Query(); $query->from("user") ->where(["exists",(new Query())->select('user_id')->from('order')->where(['user.id' => 'order.user_id'])]);