萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

SQL UNION 與 UNION ALL 深度解析:語法、去重、性能與最佳實踐

核心區別

特性UNIONUNION ALL
去重是(DISTINCT)否(保留所有行)
排序隱式排序去重無排序,直接拼接
性能慢(臨時表+排序+去重)快(流式輸出)
適用場景需要唯一結果集明確無重複、或允許重複、性能敏感

語法規則

  1. 每個 SELECT 列數相同
  2. 對應位置列類型兼容(隱式轉換或顯式 CAST)
  3. 列名以第一個 SELECT 為準
  4. ORDER BY/LIMIT 只能放在最後,或包裹子查詢

基礎示例

-- 表 A
id | name
1  | Alice
2  | Bob

-- 表 B
id | name
2  | Bob
3  | Cindy

-- UNION(去重)
SELECT * FROM A UNION SELECT * FROM B;
-- 結果:1 Alice, 2 Bob, 3 Cindy  (3 行)

-- UNION ALL(不去重)
SELECT * FROM A UNION ALL SELECT * FROM B;
-- 結果:1 Alice, 2 Bob, 2 Bob, 3 Cindy  (4 行)

進階用法

帶排序和限制

-- 錯誤:ORDER BY 不能在中間
SELECT * FROM A ORDER BY id UNION SELECT * FROM B;

-- 正確:包裹子查詢
SELECT * FROM (
    SELECT * FROM A
    UNION ALL
    SELECT * FROM B
) AS combined
ORDER BY id LIMIT 5;

帶來源標識

SELECT id, name, 'A' AS source FROM A
UNION ALL
SELECT id, name, 'B' AS source FROM B
ORDER BY source, id;

遞歸 CTE 替代 UNION ALL(MySQL 8.0+)

WITH RECURSIVE nums AS (
    SELECT 1 AS n
    UNION ALL
    SELECT n+1 FROM nums WHERE n < 100
)
SELECT * FROM nums;

性能實測(100 萬行 × 2 表)

操作耗時臨時表說明
UNION3.2 sYes (Memory -> Disk)排序去重開銷大
UNION ALL0.4 sNo流式輸出,無排序

避坑指南

  • 數據類型不一致:SELECT 1 UNION SELECT 'a' → 隱式轉換導致全表掃描/報錯 → 顯式 CAST
  • 字符集/排序規則衝突:指定 COLLATE 或統一表定義
  • 大字段(BLOB/TEXT):UNION 會強制創建臨時表拷貝大字段 → 只選必要列
  • LIMIT 在子查詢:(SELECT * FROM A LIMIT 10) UNION (SELECT * FROM B LIMIT 10) 先限制再合並,比全量 UNION 再 LIMIT 快得多

實戰模式

分頁聯合查詢

-- 需求:A 表和 B 表合並分頁,每頁 20 條
-- 方案:游標分頁(Keyset Pagination)
SELECT * FROM (
    SELECT id, col, 'A' src FROM A WHERE id > :last_id
    UNION ALL
    SELECT id, col, 'B' src FROM B WHERE id > :last_id
) AS u
ORDER BY id LIMIT 20;

歷史表+當前表查詢

SELECT * FROM orders_current WHERE user_id = 123
UNION ALL
SELECT * FROM orders_history WHERE user_id = 123
ORDER BY created_at DESC;

異構數據源合並(聯邦查詢)

-- FEDERATED 引擎或應用層合並
(SELECT * FROM mysql_db.orders WHERE ...)
UNION ALL
(SELECT * FROM pg_db.orders WHERE ...);  -- 需應用層或中間件

總結決策樹

  1. 業務是否允許重複行?→ 是 → UNION ALL
  2. 否 → 結果集是否天然無重複(如主鍵不重疊、時間範圍不重疊)?→ 是 → UNION ALL(標註業務保證)
  3. 否 → 結果集較小(<10萬行)?→ 是 → UNION
  4. 否 → 考慮:應用層合並、分頁游標、臨時表分步、或接受近似去重
copyright © 萬盛學電腦網 all rights reserved