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

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

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

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

jf_ro2CN3Fa ? 來(lái)源:芋道源碼 ? 2023-10-31 15:40 ? 次閱讀


先總結(jié):

  1. 數(shù)據(jù)量小的時(shí)候,用join更劃算
  2. 數(shù)據(jù)量大的時(shí)候,join的成本更高,但相對(duì)來(lái)說(shuō)join的速度會(huì)更快
  3. 數(shù)據(jù)量過(guò)大的時(shí)候,in的數(shù)據(jù)量過(guò)多,會(huì)有無(wú)法執(zhí)行SQL的問(wèn)題,待解決

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

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

以下實(shí)驗(yàn)僅在本機(jī)電腦試驗(yàn)

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

1、用戶(hù)表

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'手機(jī)號(hào)',
`create_time`datetimeNOTNULLCOMMENT'創(chuàng)建時(shí)間',
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 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶(hù)小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶(hù)、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

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

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

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

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

下面從三個(gè)維度來(lái)看

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

1、join

JOIN:

explainformat=jsonselectorder.id,price,user.`name`from`order`joinuseronorder.user_id=user.id;

子查詢(xún):

selectorder.id,price,user.`name`from`order`,userwhereuser_id=user.id;
2894560e-779a-11ee-939d-92fbcf53809c.jpg

2、分開(kāi)查

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查出來(lái)的所有用戶(hù)id]
28a6c58c-779a-11ee-939d-92fbcf53809c.jpg

如此看來(lái),分開(kāi)查和join查的成本并沒(méi)有相差許多

3、代碼層面

主要用php原生寫(xiě)了腳本,用ab進(jìn)行10個(gè)同時(shí)的請(qǐng)求,看下時(shí)間,進(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'));//獲取訂單中的用戶(hù)id
$result=$mysqli->query("select`id`,`name`from`user`whereidin({$userIds})");
$users=$result->fetch_all(MYSQLI_ASSOC);//獲取這些用戶(hù)的姓名

//將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

看時(shí)間的話,明顯join更快一些

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

  • 項(xiàng)目地址: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、分開(kāi)

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ù)的情況

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

1、join

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

2、分開(kāi)

order

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

user

order查出來(lái)的結(jié)果過(guò)長(zhǎng)了,,,

3、代碼層面

in

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

join

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

四、到底怎么才能更好

注:對(duì)于本機(jī)來(lái)說(shuō)100000條數(shù)據(jù)不少了,更大的數(shù)據(jù)量害怕電腦卡死

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

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

感覺(jué)這兩個(gè)方法都不是太好,各位小伙伴,有沒(méi)有更好的方法呢?


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

    關(guān)注

    1

    文章

    817

    瀏覽量

    26623

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

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

收藏 人收藏

    評(píng)論

    相關(guān)推薦

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

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

    到底是arduino還是51?

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

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

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

    PLC到底是什么?

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

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

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

    mysql中的7種JOIN

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

    請(qǐng)問(wèn)一下eMMC真能優(yōu)化成UFS?手機(jī)閃存到底是指什么?

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

    請(qǐng)問(wèn)一下在使用stm32 rtc的時(shí)候到底是選用LSI還是LSE?

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

    請(qǐng)問(wèn)一下電腦的控制器到底是什么?

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

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

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

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

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

    請(qǐng)問(wèn)一下ARM Cortex A9的核心(4核心) 到底是多少HZ

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

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

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

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

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

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

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