首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL LEFT JOIN 右表數據不唯一導致結果膨脹?子查詢去重+聚合完美解決

     編輯:MySQL 綜合教學

MySQL LEFT JOIN 右表數據不唯一導致結果膨脹?子查詢去重+聚合完美解決

LEFT JOIN 是以左表為基準、右表匹配的連接方式。當右表關聯字段存在重複值(1:N 關係)時,結果集行數會超過左表,導致報表重複、統計失真。本文通過「會員-登錄日誌」實戰案例,演示如何用子查詢聚合保證右表唯一性,獲得預期的 1:1 或 1:0 結果。

基礎語法回顧

SELECT A.*, B.col
FROM A
LEFT JOIN B ON A.id = B.a_id;
-- 左表 A 全量返回,右表 B 匹配不到則 NULL

問題場景:會員表與登錄日誌表

-- member 表(左表)
+----+----------+
| id | username |
+----+----------+
| 1  | Alice    |
| 2  | Bob      |
+----+----------+

-- member_login_log 表(右表,同一用戶多條登錄記錄)
+----+-----+------------+
| id | uid | logindate  |
+----+-----+------------+
| 1  | 1   | 2024-01-10 |
| 2  | 1   | 2024-01-15 |
| 3  | 2   | 2024-01-12 |
+----+-----+------------+

錯誤示範:直接 LEFT JOIN 導致行數膨脹

SELECT a.id, a.username, b.logindate
FROM member a
LEFT JOIN member_login_log b ON a.id = b.uid;

-- 結果:Alice 出現兩行,Bob 一行,共 3 行(預期 2 行)
+----+----------+------------+
| id | username | logindate  |
+----+----------+------------+
| 1  | Alice    | 2024-01-10 |
| 1  | Alice    | 2024-01-15 |  ← 重複行
| 2  | Bob      | 2024-01-12 |
+----+----------+------------+

正確方案:子查詢聚合右表保證唯一

業務需求:查詢每位會員的最後登錄日期。

SELECT a.id, a.username, b.last_login
FROM member a
LEFT JOIN (
    SELECT uid, MAX(logindate) AS last_login
    FROM member_login_log
    GROUP BY uid
) b ON a.id = b.uid;

-- 結果:完美 1:1/1:0,共 2 行
+----+----------+------------+
| id | username | last_login |
+----+----------+------------+
| 1  | Alice    | 2024-01-15 |
| 2  | Bob      | 2024-01-12 |
+----+----------+------------+

方案對比與選擇指南

方案適用場景優點缺點
子查詢 + GROUP BY 聚合需取最新/最舊/聚合值邏輯清晰、標準 SQL、優化器友好大表聚合可能慢,需適當索引
ROW_NUMBER() 窗口函數 (MySQL 8.0+)需保留完整行信息一次掃描、可取任意列版本要求高
關聯子查詢 SELECT (SELECT MAX...)簡單標量子查詢寫法簡潔大表性能差,優化器難下推
應用層去重極簡查詢、結果集小SQL 簡單網絡傳輸浪費、不推薦

索引優化建議

  • 右表 (uid, logindate) 建立聯合索引,支援 GROUP BY uid 且 MAX(logindate) 可走索引掃描。
  • 左表 id 為主鍵,天然最優。
  • 若右表極大,考慮物化視圖/汇总表定時刷新。

設計層面的反思

若業務頻繁出現「左表 1:N 右表」且需 JOIN,說明表設計可能未達到 3NF:

  • 右表是否應拆分為「主表 + 明細表」?
  • 是否缺少「最新狀態」冗余字段(如 member.last_login)以避免 JOIN?
  • 是否可用寬表/物化視圖預聚合?

記住:LEFT JOIN 兩表最好保持 1:1 或 1:0 關係,若右表不唯一,必須在 JOIN 前通過子查詢聚合/去重,否則結果語義模糊、性能難控。

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