首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL LEFT JOIN 與 RIGHT JOIN 實戰詳解:語法、執行流程、IS NULL 反向查詢與效能優化

     編輯:MySQL 資料庫相關知識

前言

LEFT JOIN 與 RIGHT JOIN 是外連接的兩種形式,核心差異在於**保留哪一側表的所有行**。本文以實戰範例詳細解析語法、執行流程、IS NULL 反向查詢模式、與 INNER JOIN 的效能差異,並給出優化建議。

一、LEFT JOIN

1.1 語法與語義

SELECT a.aid, a.title, u.username
FROM article AS a
LEFT JOIN user AS u ON a.uid = u.uid;
  • **保留左表 (article) 所有行**。
  • 右表 (user) 無匹配行時,右表欄位填 NULL。
  • 等價於 article LEFT OUTER JOIN user。

1.2 執行流程

  1. 掃描左表 (或由 WHERE 過濾後的左表結果集)。
  2. 對每行左表,依 ON 條件在右表尋找匹配 (利用右表索引)。
  3. 找到 → 合併輸出;找不到 → 右表欄位置 NULL 輸出。

1.3 範例資料與結果

article 表:
aid | title       | uid
1   | 'Hello'     | 1
2   | 'World'     | 2
3   | 'Foo'       | 3
4   | 'Orphan'    | 99  (user 無 uid=99)

user 表:
uid | username
1   | 'Alice'
2   | 'Bob'
3   | 'Charlie'

查詢結果:
aid | title   | username
1   | Hello   | Alice
2   | World   | Bob
3   | Foo     | Charlie
4   | Orphan  | NULL    -- 關鍵:左表保留,右表 NULL

1.4 IS NULL 反向查詢:找出無作者的文章

SELECT a.aid, a.title
FROM article a
LEFT JOIN user u ON a.uid = u.uid
WHERE u.uid IS NULL;  -- 右表主鍵為 NULL 即無匹配

**注意**:必須判斷右表**主鍵或非空唯一鍵**為 NULL,不可判斷可空欄位 (可能資料本身為 NULL)。

二、RIGHT JOIN

2.1 語法與語義

SELECT a.aid, a.title, u.username
FROM article a
RIGHT JOIN user u ON a.uid = u.uid;
  • **保留右表 (user) 所有行**。
  • 左表無匹配 → 左表欄位填 NULL。
  • 語意與 LEFT JOIN 互換:A RIGHT JOIN B ≡ B LEFT JOIN A。

2.2 範例結果

aid | title   | username
1   | Hello   | Alice
2   | World   | Bob
3   | Foo     | Charlie
NULL| NULL    | David   -- 右表保留,左表 NULL (假設 user 有 uid=4 David)

2.3 IS NULL 反向查詢:找出無文章的用戶

SELECT u.username
FROM article a
RIGHT JOIN user u ON a.uid = u.uid
WHERE a.aid IS NULL;

三、LEFT JOIN vs RIGHT JOIN 選擇原則

  • **習慣統一用 LEFT JOIN**:將「主表/驅動表」放左邊,閱讀順序符合直覺 (從主表出發關聯)。
  • 避免混用導致邏輯混淆;必要時重寫為 LEFT JOIN。

四、外連接效能與優化

4.1 外連接 vs 內連接

連接類型結果集大小優化器選擇
INNER JOIN較小 (僅匹配行)優先選擇,可交換驅動表順序
LEFT/RIGHT JOIN較大 (含保留側所有行)驅動表固定為保留側,優化空間較小

**建議**:若業務邏輯確定兩側必有匹配 (如外鍵關係且無孤兒資料),**改用 INNER JOIN** 讓優化器自由選擇最佳驅動表。

4.2 索引策略

  • **被驅動表 (右表) 關聯欄位必須有索引** (ON a.uid = u.uid → user.uid 有索引)。
  • 驅動表 (左表) WHERE 過濾欄位有索引可減少驅動行數。
  • 複合索引覆蓋 SELECT 欄位可避免回表 (Using index)。

4.3 條件下推陷阱

-- 錯誤:WHERE 條件過濾右表,導致外連接退化為內連接
SELECT * FROM article a
LEFT JOIN user u ON a.uid = u.uid
WHERE u.status = 1;  -- u.status=1 會過濾掉 u 為 NULL 的行

-- 正確:將右表條件移至 ON 子句
SELECT * FROM article a
LEFT JOIN user u ON a.uid = u.uid AND u.status = 1;

五、多表外連接鏈

SELECT a.title, u.username, c.name AS category
FROM article a
LEFT JOIN user u ON a.uid = u.uid
LEFT JOIN category c ON a.cid = c.cid
WHERE a.status = 1;
  • 依序 LEFT JOIN,每步保留左側累積結果集。
  • 若中間表 (user) 為 NULL,後續 JOIN 仍以 NULL 關聯 (結果仍為 NULL)。

六、實戰:找出「從未發文」的用戶 (三種寫法對比)

-- 1. LEFT JOIN + IS NULL (經典)
SELECT u.* FROM user u
LEFT JOIN article a ON u.uid = a.uid
WHERE a.aid IS NULL;

-- 2. NOT EXISTS (語意清晰、短路)
SELECT u.* FROM user u
WHERE NOT EXISTS (SELECT 1 FROM article a WHERE a.uid = u.uid);

-- 3. NOT IN (注意 NULL 陷阱)
SELECT u.* FROM user u
WHERE u.uid NOT IN (SELECT uid FROM article WHERE uid IS NOT NULL);

**效能**:MySQL 5.6+ 半連接優化下,三者通常同樣執行計畫 (type=ref, Extra=Using index),推薦 NOT EXISTS 或 LEFT JOIN。


結語: LEFT JOIN 是外連接的標準寫法,配合 IS NULL 反向查詢解決「缺失關聯」問題。核心優化點:**被驅動表關聯欄位建索引、右表條件寫在 ON 不寫在 WHERE、業務允許時優先 INNER JOIN**。掌握這三點,外連接不再是效能黑盒。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved