UNION 與 ORDER BY 結合時,優先級歧義常導致結果不符預期。MySQL 官方文檔建議顯式加括號明確語義。本文通過實測案例,詳細解析三種寫法的差異、LIMIT 的關鍵作用、UNION 三種變體的去重行為。
(SELECT a FROM tbl WHERE a=10 AND b=1)
UNION
(SELECT a FROM tbl WHERE a=11 AND b=2)
ORDER BY a LIMIT 10;
→ 先 UNION,再對合併結果集 ORDER BY。
(SELECT a FROM tbl WHERE a=10 AND b=1 ORDER BY a LIMIT 10)
UNION
(SELECT a FROM tbl WHERE a=11 AND b=2 ORDER BY a LIMIT 10);
→ 每個子查詢各自排序並 LIMIT,再 UNION 合併(不保證全局有序)。
SELECT a FROM tbl WHERE a=10 AND b=1
UNION
SELECT a FROM tbl WHERE a=11 AND b=2
ORDER BY a LIMIT 10;
實測結果:MySQL 預設按場景 1 執行(先 UNION 後 ORDER BY)。但強烈建議加括號,消除歧義、提升可讀性、避免版本差異。
單個 SELECT 子句中的
ORDER BY必須配合LIMIT才生效。否則優化器會將其視為無意義排序並直接移除。
-- 生效:有 LIMIT
(SELECT a FROM tbl WHERE a=10 ORDER BY a LIMIT 10)
-- 失效:無 LIMIT,ORDER BY 被優化掉
(SELECT a FROM tbl WHERE a=10 ORDER BY a)
| 語法 | 去重 | 效能 | 使用建議 |
|---|---|---|---|
UNION | ✅ 去重(相當於 UNION DISTINCT) | 需排序/哈希去重,較慢 | 業務要求結果唯一 |
UNION DISTINCT | ✅ 明確去重 | 同 UNION | 語義更清晰 |
UNION ALL | ❌ 不去重,直接合併所有行 | 最快,無額外開銷 | 明確允許重複、或已知無重複、效能敏感場景 |
-- 去重
SELECT id FROM t1 WHERE status=1
UNION
SELECT id FROM t2 WHERE status=1;
-- 不去重,效能更好
SELECT id FROM t1 WHERE status=1
UNION ALL
SELECT id FROM t2 WHERE status=1;
(SELECT id, title, 'news' AS type FROM news WHERE cat_id=1 ORDER BY id DESC LIMIT 10)
UNION ALL
(SELECT id, title, 'blog' AS type FROM blog WHERE cat_id=1 ORDER BY id DESC LIMIT 10)
ORDER BY id DESC LIMIT 10;
→ 各表取 Top 10,合併後再取 Top 10。適用於「多表聯合分頁」但無法保證全局準確分頁(需應用層合併或全局視圖)。
(SELECT email FROM users WHERE active=1)
UNION
(SELECT email FROM subscribers WHERE confirmed=1)
UNION
(SELECT email FROM leads WHERE opted_in=1)
ORDER BY email;
→ 三源郵箱去重合併,最終有序輸出。
ORDER BY 1),避免歧義UNION ALLtmp_table_size/max_heap_table_size 會落盤,極慢UNION 與 ORDER BY 的優先級歧義,加括號即可徹底解決。記住:子查詢 ORDER BY 必配 LIMIT,去重用 UNION,不去重用 UNION ALL。將這些規範寫入團隊 SQL 開發規範,能避免 90% 的聯合查詢 Bug。