0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

MySQL到底是join性能好,還是in一下更快呢?

jf_ro2CN3Fa ? 來源:芋道源碼 ? 2023-10-31 15:40 ? 次閱讀


先總結(jié):

  1. 數(shù)據(jù)量小的時候,用join更劃算
  2. 數(shù)據(jù)量大的時候,join的成本更高,但相對來說join的速度會更快
  3. 數(shù)據(jù)量過大的時候,in的數(shù)據(jù)量過多,會有無法執(zhí)行SQL的問題,待解決

事情是這樣的,去年入職的新公司,之后在代碼review的時候被提出說,不要寫join,join耗性能還是慢來著,當(dāng)時也是真的沒有多想,那就寫in好了,最近發(fā)現(xiàn)in的數(shù)據(jù)量過大的時候會導(dǎo)致sql慢,甚至sql太長,直接報錯了。

這次來淺究一下,到底是in好還是join好,僅目前認(rèn)知探尋,有不對之處歡迎指正

以下實驗僅在本機電腦試驗

一、表結(jié)構(gòu)

1、用戶表

2878693a-779a-11ee-939d-92fbcf53809c.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
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)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 視頻教程:https://doc.iocoder.cn/video/

二、先來試少量數(shù)據(jù)的情況

用戶表插一千條隨機生成的數(shù)據(jù),訂單表插一百條隨機數(shù)據(jù)

查下所有的訂單以及訂單對應(yīng)的用戶

下面從三個維度來看

多表連接查詢成本 = 一次驅(qū)動表成本 + 從驅(qū)動表查出的記錄數(shù) * 一次被驅(qū)動表的成本

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

2、分開查

select`id`,price,user_idfrom`order`;
289b8532-779a-11ee-939d-92fbcf53809c.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

如此看來,分開查和join查的成本并沒有相差許多

3、代碼層面

主要用php原生寫了腳本,用ab進(jìn)行10個同時的請求,看下時間,進(jìn)行比較

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);

//關(guān)閉mysql連接

$mysqli->close();
28bd9a28-779a-11ee-939d-92fbcf53809c.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

看時間的話,明顯join更快一些

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://github.com/YunaiV/yudao-cloud
  • 視頻教程:https://doc.iocoder.cn/video/

三、試下多一些數(shù)據(jù)的情況

user表現(xiàn)在10000條數(shù)據(jù),order表10000條試下

1、join

28d71b1a-779a-11ee-939d-92fbcf53809c.jpg

2、分開

order

28e1cbe6-779a-11ee-939d-92fbcf53809c.jpg

user

28f0428e-779a-11ee-939d-92fbcf53809c.jpg

3、代碼層面

in

2902983a-779a-11ee-939d-92fbcf53809c.jpg

join

29180a4e-779a-11ee-939d-92fbcf53809c.jpg

三、試下多一些數(shù)據(jù)的情況

隨機插入后user表十萬條數(shù)據(jù),order表一百萬條試下

1、join

2927e5d6-779a-11ee-939d-92fbcf53809c.jpg

2、分開

order

2932ea80-779a-11ee-939d-92fbcf53809c.jpg

user

order查出來的結(jié)果過長了,,,

3、代碼層面

in

293feea6-779a-11ee-939d-92fbcf53809c.jpg

join

294aab20-779a-11ee-939d-92fbcf53809c.jpg

四、到底怎么才能更好

注:對于本機來說100000條數(shù)據(jù)不少了,更大的數(shù)據(jù)量害怕電腦卡死

總的來說,當(dāng)數(shù)據(jù)量小時,可能一頁數(shù)據(jù)就夠放的時候,join的成本和速度都更好。數(shù)據(jù)量大的時候確實分開查的成本更低,但是由于數(shù)據(jù)量大,造成循環(huán)的成本更多,代碼執(zhí)行的時間也就越長。

實驗過程中發(fā)現(xiàn),當(dāng)in的數(shù)據(jù)量過大的時候,sql過長會無法執(zhí)行,可能還要拆開多條sql進(jìn)行查詢,這樣的查詢成本和時間一定也會更長,而且如果有分頁的需求的話,也無法滿足。。。

感覺這兩個方法都不是太好,各位小伙伴,有沒有更好的方法呢?


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • MySQL
    +關(guān)注

    關(guān)注

    1

    文章

    792

    瀏覽量

    26351

原文標(biāo)題:MySQL到底是 join 性能好,還是in一下更快呢?

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    射頻設(shè)計中的互調(diào)失真到底是如何發(fā)生的?如何預(yù)防?

    互調(diào)是射頻設(shè)計避免對的個問題,到底是如何發(fā)生的?我們起來學(xué)習(xí)。
    發(fā)表于 08-12 11:30 ?1244次閱讀
    射頻設(shè)計中的互調(diào)失真<b class='flag-5'>到底是</b>如何發(fā)生的<b class='flag-5'>呢</b>?如何預(yù)防?

    到底是arduino還是51

    最近對arduino很感冒,對51單片機的熱情降低了很多,到底是arduino還是51,有點點糾結(jié)。求助,幫小弟解析一下。謝謝了!
    發(fā)表于 05-23 22:29

    目前國產(chǎn)CPLD達(dá)到怎樣水平了,有沒有性能好的幫忙推薦一下

    目前國產(chǎn)CPLD達(dá)到怎樣水平了,有沒有性能好的幫忙推薦一下
    發(fā)表于 02-26 11:34

    PLC到底是什么?

    PLC到底是什么?
    發(fā)表于 10-10 09:30

    兩層板設(shè)計晶振下方到底是挖空還是鋪地?

    請教給位大神,晶振下方到底是挖空還是鋪地& p& V2 I/ Q- M# O比如說我兩層板,頂層是貼片晶振,那么底層是挖空還是鋪地
    發(fā)表于 12-26 11:55

    mysql中的7種JOIN

    mysqlJOIN大匯總
    發(fā)表于 03-11 11:18

    請問一下eMMC真能優(yōu)化成UFS?手機閃存到底是指什么?

    請問一下eMMC真能優(yōu)化成UFS?手機閃存到底是指什么?
    發(fā)表于 06-18 07:55

    請問一下在使用stm32 rtc的時候到底是選用LSI還是LSE?

    請問一下在使用stm32 rtc的時候到底是選用LSI還是LSE?
    發(fā)表于 09-23 06:16

    請問一下電腦的控制器到底是什么?

    請問一下電腦的控制器到底是什么?
    發(fā)表于 10-28 07:35

    到底是學(xué)STM32還是學(xué)嵌入式linux

    一下,希望對大家有所啟發(fā)。02STM32確實首先得承認(rèn)STM32確實,好到STM32都成了單片機MCU的代名詞了,現(xiàn)在很多人甚至說單片機時默認(rèn)就..
    發(fā)表于 11-04 08:50

    到底是學(xué)STM32還是學(xué)嵌入式linux

    01話 題經(jīng)常有大學(xué)生同學(xué)糾結(jié):我到底是學(xué)STM32還是學(xué)嵌入式linux。這個問題很多人都會有自己的看法,今天我試著從多個角度,把我了解到的事實講一下,希望對大家有所啟發(fā)。STM3202STM32
    發(fā)表于 02-07 07:06

    請問一下ARM Cortex A9的核心(4核心) 到底是多少HZ?

    請問一下ARM Cortex A9的核心(4核心) 到底是多少HZ?
    發(fā)表于 08-25 15:45

    加的全面屏新機最新消息:到底是加5T還是加6

    加5的造就了新代神話,發(fā)布至今大獲全勝。由于其“發(fā)燒”的配置加上流暢的系統(tǒng),飽受國內(nèi)外消費者青睞。加5的熱度剛過,加的全面屏新機又有消息了,
    發(fā)表于 10-10 11:04 ?2389次閱讀

    如何優(yōu)化MySQL中的join語句

    mysql中,join 主要有Nested Loop、Hash Join、Merge Join 這三種方式,我們今天來看一下最普遍 Nes
    的頭像 發(fā)表于 04-24 17:03 ?752次閱讀
    如何優(yōu)化<b class='flag-5'>MySQL</b>中的<b class='flag-5'>join</b>語句

    查詢SQL在mysql內(nèi)部是如何執(zhí)行?

    我們知道在mySQL客戶端,輸入條查詢SQL,然后看到返回查詢的結(jié)果。這條查詢語句在 MySQL 內(nèi)部到底是如何執(zhí)行的?本文跟大家探討
    的頭像 發(fā)表于 01-22 14:53 ?481次閱讀
    查詢SQL在<b class='flag-5'>mysql</b>內(nèi)部是如何執(zhí)行?