MySQL?Join使用之大表關(guān)聯(lián)小表及小表關(guān)聯(lián)大表
一、問題背景:為什么會問這個問題?
面試官問你這個問題,目的并不是讓你說“哪個表放前哪個表放后”那么簡單,而是考察你是否理解:
SQL Join 的執(zhí)行原理(尤其是 Nested Loop Join);
表的大小、順序、索引對執(zhí)行性能的影響;
實戰(zhàn)中有沒有優(yōu)化 Join 性能的經(jīng)驗;
是否能借助 EXPLAIN 分析執(zhí)行計劃。
二、SQL Join 的執(zhí)行機(jī)制(MySQL)
在 MySQL 中,主要使用的是 Nested Loop Join(嵌套循環(huán)連接):
執(zhí)行原理:
for row in 外層表(驅(qū)動表):
for row2 in 內(nèi)層表(被驅(qū)動表):
if row 與 row2 滿足 join 條件:
返回結(jié)果注意:
SQL 寫法中:
SELECT * FROM A JOIN B ON ...
默認(rèn)是A為驅(qū)動表,B為被驅(qū)動表。實際執(zhí)行時,MySQL 可能會基于成本優(yōu)化器調(diào)整順序(通過 EXPLAIN 可見)。
三、什么是大表?什么是小表?
| 表類型 | 行數(shù)(示意) | 特點 |
|---|---|---|
| 小表 | 千行以內(nèi) | 維度表、字典表、配置表等 |
| 大表 | 萬行、百萬級 | 交易表、日志表、訂單表等 |
四、大表驅(qū)動小表 vs 小表驅(qū)動大表:有何區(qū)別?
區(qū)別在于:驅(qū)動表每行都要去被驅(qū)動表中匹配一次
驅(qū)動表越大,執(zhí)行次數(shù)越多
被驅(qū)動表必須有合適的索引,否則每次匹配都全表掃
五、舉例說明(含 SQL + 執(zhí)行計劃)
示例:訂單表(大表) + 商品表(小表)
-- 大表:order (1000w) -- 小表:product (1w)
錯誤方式:大表驅(qū)動小表(性能差)
SELECT * FROM order o JOIN product p ON o.product_id = p.id;
執(zhí)行邏輯:
遍歷訂單表的每一行(1000w次)
每一行去 product 中找匹配行
?? 如果 product.id 無索引:每次都要全表掃描 product → 1000w × 1w → 超慢!
正確方式:小表驅(qū)動大表(性能優(yōu))
SELECT * FROM product p JOIN order o ON p.id =o.product_id;
執(zhí)行邏輯:
遍歷 product 表的每一行(1w次)
每次去 order 表查 product_id = xxx 的記錄
若
order.product_id有索引,則快速定位
性能大幅提升,尤其在 order 表是大表時。
六、執(zhí)行計劃分析(EXPLAIN)
EXPLAIN SELECT * FROM order o JOIN product p ON o.product_id = p.id;
| id | select_type | table | type | key | rows | Extra |
|---|---|---|---|---|---|---|
| 1 | SIMPLE | o | ALL | NULL | 10,000,000 | |
| 1 | SIMPLE | p | ALL | NULL | 10,000 | Using join buffer (Block Nested Loop) |
?? 都是全表掃描,說明沒優(yōu)化!
七、優(yōu)化建議總結(jié)(面試可答)
1. 盡量使用小表做驅(qū)動表
小表遍歷次數(shù)少,整體性能高
2. 被驅(qū)動表要建好關(guān)聯(lián)字段的索引
沒有索引就會退化成 Block Nested Loop + join buffer,耗時大
3. 盡量讓 Join 條件包含等值匹配(=)
4. 避免 Join 條件計算、函數(shù)、隱式類型轉(zhuǎn)換(會導(dǎo)致索引失效)
5. 使用STRAIGHT_JOIN強(qiáng)制 Join 順序(MySQL 默認(rèn)優(yōu)化器可調(diào)換 Join 順序)
SELECT * FROM small s STRAIGHT_JOIN big b ON s.id = b.id;
八、真實面試回答模板(結(jié)構(gòu)化)
我理解面試官這個問題主要是想考我是否清楚 Join 的執(zhí)行原理以及實際優(yōu)化經(jīng)驗。MySQL Join 默認(rèn)使用的是嵌套循環(huán)(Nested Loop Join),左表作為驅(qū)動表,右表為被驅(qū)動表。我們在項目中一般優(yōu)先選小表作為驅(qū)動表,被驅(qū)動表則需要建立好關(guān)聯(lián)字段索引,這樣可以大幅減少掃描次數(shù),提升執(zhí)行效率。如果大表做驅(qū)動表,而被驅(qū)動表沒有索引,就可能出現(xiàn)成千上萬次的全表掃描,性能會非常差。我們也會通過 EXPLAIN 查看 SQL 的執(zhí)行計劃,關(guān)注 type 是否是 ALL(表示全表掃)、rows 是否偏大、key 是否命中索引等字段。如果必要,也會通過 STRAIGHT_JOIN 強(qiáng)制指定小表為驅(qū)動表。這個問題我在實際優(yōu)化中遇到過好幾次,比如商品表關(guān)聯(lián)類目表、訂單表關(guān)聯(lián)用戶表等場景。
九、思維導(dǎo)圖版(簡化復(fù)習(xí))
大表 vs 小表關(guān)聯(lián)問題
├── Join 執(zhí)行原理:Nested Loop
│ └── 左表為驅(qū)動表,右表為被驅(qū)動表
├── 性能影響:
│ ├── 驅(qū)動表大 → 循環(huán)次數(shù)多
│ ├── 被驅(qū)動表無索引 → 每次全表掃
├── 最佳實踐:
│ ├── 小表做驅(qū)動
│ ├── 被驅(qū)動表建索引
│ └── 使用 EXPLAIN 分析執(zhí)行計劃
└── 補(bǔ)充技巧:
├── STRAIGHT_JOIN 控制順序
├── 避免函數(shù)/類型轉(zhuǎn)換
└── 等值 Join 優(yōu)于范圍 Join
總結(jié)
到此這篇關(guān)于MySQL Join使用之大表關(guān)聯(lián)小表及小表關(guān)聯(lián)大表的文章就介紹到這了,更多相關(guān)MySQL Join大表小表關(guān)聯(lián)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql跨數(shù)據(jù)庫復(fù)制表(在同一IP地址中)示例
這篇文章主要介紹了mysql跨數(shù)據(jù)庫復(fù)制表(在同一IP地址中)示例,需要的朋友可以參考下2014-03-03
MYSQL 關(guān)于兩個經(jīng)緯度之間的距離由近及遠(yuǎn)排序
本篇文章是對MYSQL中關(guān)于兩個經(jīng)緯度之間的距離由近及遠(yuǎn)排序的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-07-07
MySQL使用ReplicationConnection導(dǎo)致連接失效解決
這篇文章主要為大家介紹了MySQL使用ReplicationConnection導(dǎo)致連接失效問題分析解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
詳解MySQL監(jiān)控工具 mysql-monitor
這篇文章主要介紹了解MySQL監(jiān)控工具 mysql-monitor的相關(guān)知識,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2020-07-07
MySQL必備基礎(chǔ)之分組函數(shù) 聚合函數(shù) 分組查詢詳解
這篇文章主要介紹了MySQL分組函數(shù)、聚合函數(shù)、分組查詢,結(jié)合實例形式分析了MySQL查詢分組函數(shù)以及查詢聚合函數(shù)相關(guān)使用技巧,需要的朋友可以參考下2021-10-10
Mysql快速插入千萬條數(shù)據(jù)的實戰(zhàn)教程
這篇文章主要給大家介紹了關(guān)于Mysql快速插入千萬條數(shù)據(jù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03

