咱们在学习Yii2的时候,必定接触过这样的where输入数据库
$query->where(["exists",xxxx]); User::find()->where(["exists",xxxx])->all();
是的,这是MYSQL的exists关键词,今天咱们就来讲说这个exist,为了给你们更清楚的讲解,先给你们说下本文目录:缓存
什么是exists性能
exists和in的区别和使用场景学习
使用Yii2的Query Builder实现一个exists语句ui
要本身看哈。spa
为了你们学习方便,北哥在这里面创建两张表并为其添加一些数据code
一张会员表,一张会员下单表。blog
会员表数据图片
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'])]);