先總結:
- 數(shù)據(jù)量小的時候,用join更劃算
- 數(shù)據(jù)量大的時候,join的成本更高,但相對來說join的速度會更快
- 數(shù)據(jù)量過大的時候,in的數(shù)據(jù)量過多,會有無法執(zhí)行SQL的問題,待解決
事情是這樣的,去年入職的新公司,之后在代碼review的時候被提出說,不要寫join,join耗性能還是慢來著,當時也是真的沒有多想,那就寫in好了,最近發(fā)現(xiàn)in的數(shù)據(jù)量過大的時候會導致sql慢,甚至sql太長,直接報錯了。
這次來淺究一下,到底是in好還是join好,僅目前認知探尋,有不對之處歡迎指正
以下實驗僅在本機電腦試驗
一、表結構
1、用戶表
![2878693a-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4A/wKgZomVAsOSAFzc2AABoH2MXe-Y345.jpg)
CREATETABLE`user`(
`id`intNOTNULLAUTO_INCREMENT,
`name`varchar(64)CHARACTERSETutf8mb4COLLATEutf8mb4_general_ciNOTNULLCOMMENT'姓名',
`gender`smallintDEFAULTNULLCOMMENT'性別',
`mobile`varchar(11)CHARACTERSETutf8mb4COLLATEutf8mb4_general_ciNOTNULLCOMMENT'手機號',
`create_time`datetimeNOTNULLCOMMENT'創(chuàng)建時間',
PRIMARYKEY(`id`),
UNIQUEKEY`mobile`(`mobile`)USINGBTREE
)ENGINE=InnoDBAUTO_INCREMENT=1005DEFAULTCHARSET=utf8mb4COLLATE=utf8mb4_general_ci
2、訂單表
![288a61f8-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4A/wKgZomVAsOSAF_hEAABYZmHVhgg956.jpg)
CREATETABLE`order`(
`id`intunsignedNOTNULLAUTO_INCREMENT,
`price`decimal(18,2)NOTNULL,
`user_id`intNOTNULL,
`product_id`intNOTNULL,
`status`smallintNOTNULLDEFAULT'0'COMMENT'訂單狀態(tài)',
PRIMARYKEY(`id`),
KEY`user_id`(`user_id`),
KEY`product_id`(`product_id`)
)ENGINE=InnoDBAUTO_INCREMENT=202DEFAULTCHARSET=utf8mb4COLLATE=utf8mb4_general_ci
基于 Spring Boot + MyBatis Plus + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權限、多租戶、數(shù)據(jù)權限、工作流、三方登錄、支付、短信、商城等功能
- 項目地址:https://github.com/YunaiV/ruoyi-vue-pro
- 視頻教程:https://doc.iocoder.cn/video/
二、先來試少量數(shù)據(jù)的情況
用戶表插一千條隨機生成的數(shù)據(jù),訂單表插一百條隨機數(shù)據(jù)
查下所有的訂單以及訂單對應的用戶
下面從三個維度來看
多表連接查詢成本 = 一次驅動表成本 + 從驅動表查出的記錄數(shù) * 一次被驅動表的成本
1、join
JOIN:
explainformat=jsonselectorder.id,price,user.`name`from`order`joinuseronorder.user_id=user.id;
子查詢:
selectorder.id,price,user.`name`from`order`,userwhereuser_id=user.id;
![2894560e-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4A/wKgZomVAsOSAOI-nAAAvadqp6E4361.jpg)
2、分開查
select`id`,price,user_idfrom`order`;
![289b8532-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4A/wKgZomVAsOSAeTzKAAAqLu1ZEV8854.jpg)
selectnamefromuserwhereidin(8,11,20,32,49,58,64,67,97,105,113,118,129,173,179,181,210,213,215,216,224,243,244,251,280,309,319,321,336,342,344,349,353,358,363,367,374,377,380,417,418,420,435,447,449,452,454,459,461,472,480,487,498,499,515,525,525,531,564,566,580,584,586,592,595,610,633,635,640,652,658,668,674,685,687,701,718,720,733,739,745,751,758,770,771,780,806,834,841,856,856,857,858,882,934,942,983,989,994,995);[in的是order查出來的所有用戶id]
![28a6c58c-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4A/wKgZomVAsOSAenUbAAAnNlmqju0246.jpg)
如此看來,分開查和join查的成本并沒有相差許多
3、代碼層面
主要用php原生寫了腳本,用ab進行10個同時的請求,看下時間,進行比較
ab -n 100 -c 10
in
$mysqli=newmysqli('127.0.0.1','root','root','test');
if($mysqli->connect_error){
die('ConnectError('.$mysqli->connect_errno.')'.$mysqli->connect_error);
}
$result=$mysqli->query('select`id`,price,user_idfrom`order`');
$orders=$result->fetch_all(MYSQLI_ASSOC);
$userIds=implode(',',array_column($orders,'user_id'));//獲取訂單中的用戶id
$result=$mysqli->query("select`id`,`name`from`user`whereidin({$userIds})");
$users=$result->fetch_all(MYSQLI_ASSOC);//獲取這些用戶的姓名
//將id做數(shù)組鍵
$userRes=[];
foreach($usersas$user){
$userRes[$user['id']]=$user['name'];
}
$res=[];
//整合數(shù)據(jù)
foreach($ordersas$order){
$current=[];
$current['id']=$order['id'];
$current['price']=$order['price'];
$current['name']=$userRes[$order['user_id']]?:'';
$res[]=$current;
}
var_dump($res);
//關閉mysql連接
$mysqli->close();
![28bd9a28-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4A/wKgZomVAsOSASKWBAABIk6KkZjU219.jpg)
join
$mysqli=newmysqli('127.0.0.1','root','root','test');
if($mysqli->connect_error){
die('ConnectError('.$mysqli->connect_errno.')'.$mysqli->connect_error);
}
$result=$mysqli->query('selectorder.id,price,user.`name`from`order`joinuseronorder.user_id=user.id;');
$orders=$result->fetch_all(MYSQLI_ASSOC);
var_dump($orders);
$mysqli->close();
![28cc54dc-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4A/wKgZomVAsOWABe-cAABMHwanzbg419.jpg)
看時間的話,明顯join更快一些
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權限、多租戶、數(shù)據(jù)權限、工作流、三方登錄、支付、短信、商城等功能
三、試下多一些數(shù)據(jù)的情況
user表現(xiàn)在10000條數(shù)據(jù),order表10000條試下
1、join
![28d71b1a-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4A/wKgZomVAsOWAeaUqAAAq3e5SkUY561.jpg)
2、分開
order
![28e1cbe6-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4A/wKgZomVAsOWARKcCAAAshvXsUug991.jpg)
user
![28f0428e-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4B/wKgZomVAsOWAOaj3AAAtXkngL9c774.jpg)
3、代碼層面
in
![2902983a-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4B/wKgZomVAsOWAWRbQAABMS89cTXI843.jpg)
join
![29180a4e-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4B/wKgZomVAsOWAdi3iAABKR-y0dLo067.jpg)
三、試下多一些數(shù)據(jù)的情況
隨機插入后user表十萬條數(shù)據(jù),order表一百萬條試下
1、join
![2927e5d6-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4B/wKgZomVAsOWAQh1CAAAvy4c5ql0426.jpg)
2、分開
order
![2932ea80-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4B/wKgZomVAsOaAMQIDAAAuS9_w6GI187.jpg)
user
order查出來的結果過長了,,,
3、代碼層面
in
![293feea6-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4B/wKgZomVAsOaAbwejAABIm0J3QSs200.jpg)
join
![294aab20-779a-11ee-939d-92fbcf53809c.jpg](https://file1.elecfans.com/web2/M00/AD/4B/wKgZomVAsOaALv3TAABaQG2-g24926.jpg)
四、到底怎么才能更好
注:對于本機來說100000條數(shù)據(jù)不少了,更大的數(shù)據(jù)量害怕電腦卡死
總的來說,當數(shù)據(jù)量小時,可能一頁數(shù)據(jù)就夠放的時候,join的成本和速度都更好。數(shù)據(jù)量大的時候確實分開查的成本更低,但是由于數(shù)據(jù)量大,造成循環(huán)的成本更多,代碼執(zhí)行的時間也就越長。
實驗過程中發(fā)現(xiàn),當in的數(shù)據(jù)量過大的時候,sql過長會無法執(zhí)行,可能還要拆開多條sql進行查詢,這樣的查詢成本和時間一定也會更長,而且如果有分頁的需求的話,也無法滿足。。。
感覺這兩個方法都不是太好,各位小伙伴,有沒有更好的方法呢?
-
MySQL
+關注
關注
1文章
817瀏覽量
26628
原文標題:MySQL到底是 join 性能好,還是in一下更快呢?
文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
射頻設計中的互調(diào)失真到底是如何發(fā)生的呢?如何預防?
![射頻設計中的互調(diào)失真<b class='flag-5'>到底是</b>如何發(fā)生的<b class='flag-5'>呢</b>?如何預防?](https://file1.elecfans.com/web2/M00/90/50/wKgaomTW_XKAId9pAAArdEH-lRg514.png)
到底是arduino還是51好?
兩層板設計晶振下方到底是挖空好還是鋪地好?
到底是學STM32還是學嵌入式linux呢
到底是學STM32還是學嵌入式linux
一加的全面屏新機最新消息:到底是一加5T還是一加6呢?
查詢SQL在mysql內(nèi)部是如何執(zhí)行?
![查詢SQL在<b class='flag-5'>mysql</b>內(nèi)部是如何執(zhí)行?](https://file1.elecfans.com/web2/M00/BD/C3/wKgZomWuEViAEJdjAAAotpWrJqM184.png)
評論