全站搜索是典型的多表聯合查詢場景:用戶在一個輸入框檢索關鍵詞,需同時命中文章、課程、產品等不同業務表。本文通過實際 SQL 拆解 UNION 與 UNION ALL 的語義差異、去重機制及性能取捨。
SELECT * FROM (
SELECT `id`,`subject` FROM `article`
WHERE `active`=1 AND `subject` LIKE '%調整圖片%'
ORDER BY `add_time` DESC
) AS t1
UNION ALL
SELECT * FROM (
SELECT `id`,`class_name` AS `subject` FROM `web_class`
WHERE `active`=1 AND `class_name` LIKE '%調整圖片%'
ORDER BY `class_id` DESC
) AS t2
UNION
SELECT * FROM (
SELECT `id`,`subject` FROM `article`
WHERE `active`=1 AND (`subject` LIKE '%調整%' OR `subject` LIKE '%圖片%')
ORDER BY `add_time` DESC
) AS t3;
| 特性 | UNION ALL | UNION (DISTINCT) |
|---|---|---|
| 語義 | 直接合併所有結果集,保留重複行 | 合併後做全局去重(排序+唯一) |
| 性能 | O(N),無額外開銷 | O(N log N),需臨時表+排序/哈希去重 |
| 適用場景 | 業務確定無重複、或允許重複、極度追求速度 | 不同來源可能產生重複、需保證結果唯一 |
article 與 web_class 為異構表,主鍵空間不重疊,業務邏輯上不可能重複,直接 ALL 避免去重開銷。%調整% OR %圖片%)結果集必然包含第一分支(%調整圖片%)的所有行,若用 ALL 會產生大量重複;改用 UNION 自動去重,保證最終結果集唯一。SELECT 列數、順序、類型必須一致;第二分支用 AS subject 別名對齊第一、三分支的 subject。LIMIT N,防止全表掃描拖垮實例。%keyword% 導致全表掃描。(active, subject, add_time) 聯合索引實現 Index Only Scan。UNION ALL 是默認首選,除非業務確定需要去重。全站搜索架構演進路徑通常是:UNION → 應用層合併 → 專用搜索引擎。根據數據量與 QPS 選擇合適階段,切勿過度設計。