MySQL性能優化(六)-- in和exists

in和exists哪一個性能更優

sql腳本:mysql

/*建庫*/
create database testdb6;
use testdb6;
/* 用戶表 */
drop table if exists users;
create table users(
	id int primary key auto_increment,
	name varchar(20)
);
insert into users(name) values ('A');
insert into users(name) values ('B');
insert into users(name) values ('C');
insert into users(name) values ('D');
insert into users(name) values ('E');
insert into users(name) values ('F');
insert into users(name) values ('G');
insert into users(name) values ('H');
insert into users(name) values ('I');
insert into users(name) values ('J');

/* 訂單表 */
drop table if exists orders;
create table orders(
	id int primary key auto_increment,/*訂單id*/
	order_no varchar(20) not null,/*訂單編號*/
	title varchar(20) not null,/*訂單標題*/
	goods_num int not null,/*訂單數量*/
	money decimal(7,4) not null,/*訂單金額*/
	user_id int not null    /*訂單所屬用戶id*/
)engine=myisam default charset=utf8 ;

delimiter $$
drop procedure batch_orders $$

/* 存儲過程 */
create procedure batch_orders(in max int)
begin
declare start int default 0;
declare i int default 0;
set autocommit = 0;  
while i < max do
   set i = i + 1;
   insert into orders(order_no,title,goods_num,money,user_id) 
   values (concat('NCS-',floor(1 + rand()*1000000000000 )),concat('訂單title-',i),i%50,(100.0000+(i%50)),i%10);
 &emsp; end while;
commit;
end $$
delimiter ;

/*插入1000萬條訂單數據*/
call batch_orders(10000000);     /*插入數據的過程根據機器的性能 花費的時間不一樣,有的可能3分鐘,有的可能10分鐘*/
複製代碼

上面的sql中 訂單表中(orders) 存在user_id,而又有用戶表(users),因此咱們用orders表中user_id和user表中的id 來in 和 exists。sql

結果性能

1.where後面是小表spa

(1)select count(1) from orders o where o.user_id in(select u.id from users u); code

img

(2)select count(1) from orders o where exists (select 1 from users u where u.id = o.user_id); cdn

img

2.where後面是大表blog

(1)select count(1) from users u where u.id in (select o.user_id from orders o); ci

img

(2)select count(1) from users u where exists (select 1 from orders o where o.user_id = u.id); rem

img

分析it

咱們用下面的這兩條語句分析:

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適合於外表小而內表大的狀況。


歡迎關注個人公衆號,第一時間接收最新文章~ 搜索公衆號: 碼咖 或者 掃描下方二維碼:

img
相關文章
相關標籤/搜索