萬盛學電腦網

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

MySQL UNION 全解析:語法規則、排序陷阱與分頁實戰模式

UNION 合併多個 SELECT 結果集,去重(DISTINCT)或保留重複(ALL)。掌握其排序、分頁、欄位對齊規則,能寫出高效、正確的聯合查詢。

語法規則速查

SELECT col1, col2 FROM t1
UNION [ALL | DISTINCT]
SELECT col1, col2 FROM t2
[UNION ...]
[ORDER BY col1 [DESC]]
[LIMIT n];
  • 欄位數、順序、型別必須一致(型別隱式轉換遵循 MySQL 規則)。
  • 結果集欄位名以第一個 SELECT 為準。
  • UNION = UNION DISTINCT(去重,需排序/哈希,較慢)。
  • UNION ALL 直接拼接,效能遠優於 UNION,確定無重複時必用 ALL。

排序與 LIMIT 陷阱

錯誤:單獨 SELECT 加 ORDER BY LIMIT

(SELECT * FROM t1 ORDER BY id LIMIT 10)
UNION
(SELECT * FROM t2 ORDER BY id LIMIT 10);
-- 結果順序不保證,LIMIT 只對單側生效

正確:外層包裹統一排序分頁

SELECT * FROM (
    SELECT * FROM t1
    UNION ALL
    SELECT * FROM t2
) AS u
ORDER BY u.id DESC
LIMIT 20;

別名引用規則

-- 正確:用第一個 SELECT 的別名
(SELECT a AS b FROM t1) UNION (SELECT ...) ORDER BY b;

-- 錯誤:用原欄位名
(SELECT a AS b FROM t1) UNION (SELECT ...) ORDER BY a;  -- Unknown column 'a'

實戰模式:置頂 + 普通 分頁

部落格置頂文章優先,再按時間倒序分頁。

(
  SELECT *, 1 AS ord FROM posts WHERE is_top = 1 ORDER BY created_at DESC
)
UNION ALL
(
  SELECT *, 2 AS ord FROM posts WHERE is_top = 0 ORDER BY created_at DESC
)
ORDER BY ord, created_at DESC
LIMIT 10 OFFSET 0;
  • 子查詢各自排序,外層按 ord 分組再排序。
  • UNION ALL 避免去重開銷(置頂與普通互斥)。

雙向排序需求:前 3 條點擊最高,其餘按時間

SELECT * FROM (
    (SELECT *, 1 AS grp FROM posts ORDER BY clicks DESC LIMIT 3)
    UNION ALL
    (SELECT *, 2 AS grp FROM posts ORDER BY created_at DESC)
) AS u
ORDER BY u.grp, 
         CASE u.grp WHEN 1 THEN u.clicks END DESC,
         CASE u.grp WHEN 2 THEN u.created_at END DESC;

效能對比

寫法執行計畫關鍵字適用場景
UNION DISTINCTUsing temporary; Using filesort需去重、小結果集
UNION ALL無臨時表/排序已知無重複、大結果集、高頻介面
子查詢各自 LIMIT + 外層 ORDER BY LIMIT各子查詢用索引,外層小結果集排序分頁、置頂、異構數據源合併

最佳實踐清單

  1. 預設用 UNION ALL,確有重複才改 UNION。
  2. 欄位型別顯式 CAST 對齊,避免隱式轉換導致索引失效。
  3. 外層統一 ORDER BY/LIMIT,子查詢僅做資料準備。
  4. 大結果集考慮 UNION ALL + 應用層分頁,避免深分頁 OFFSET 掃描。

善用 UNION ALL + 外層排序分頁,即可優雅解決「多源合併、置頂優先、異構排序」等複雜查詢需求。

copyright © 萬盛學電腦網 all rights reserved