作為長年在第一線與海量資料打交道的後端開發者,在複雜的業務系統開發中,處理重複資料是我們繞不開的命題。為了保證輸出資料的唯一性,我們經常在 SQL 中使用 `DISTINCT` 關鍵字,或者利用全欄位 `GROUP BY` 來實現語意上的去重。
然而,隨著業務資料的指數級成長,這類去重操作屢屢成為拖垮系統查詢效能的「隱形殺手」。最近,團隊在進行底層基礎軟體的遷移與效能攻堅,我們將核心業務線遷移至了電科金倉資料庫 Kingbase。在深度剖析慢查詢日誌與底層執行計畫時,我發現現代資料庫的最佳化器早已跨越了單純比對物理成本的階段,進化出基於編譯邏輯推理的高級智慧核心。
今天,我們就結合具體的 SQL 實作和極端場景下的底層執行計畫對比,硬核拆解現代資料庫是如何透過「常值推導」等語意重寫手段,優雅且徹底地消滅去重效能瓶頸的。 
@[toc]
要理解最佳化的精妙,我們首先要明白傳統資料庫在處理去重時有多麼「死板」。在傳統的執行引擎眼中,無論是 DISTINCT 還是 GROUP BY 去重,底層的物理實現邏輯基本都是一套標準流程:全表或索引掃描過濾目標資料 -> 將資料送入記憶體建立雜湊表或進行排序 -> 逐列分組比對剔除重複項。
為了直觀展示這種效能浪費,我們在資料庫中建構了一個包含海量冗餘資料的測試表 s1,並模擬了一個需要對常數條件進行去重的查詢場景:
sql 體驗AI代碼助手 代碼解讀複製代碼-- 傳統的去重查詢寫法(使用 GROUP BY 替代 DISTINCT 實現語意去重)
EXPLAIN ANALYZE SELECT a, b FROM s1 WHERE a=1 AND b=1 GROUP BY a, b;

效能災難分析:如上圖的執行計畫所示,資料庫極其「老實」地執行了並行全表掃描(Parallel Seq Scan),把滿足條件的冗餘資料全部撈了出來。接著,啟動了 Group 算子,在記憶體中為這些長得一模一樣的資料進行毫無意義的分組比對。整個過程白白消耗了 16.717 毫秒。不僅浪費 CPU,還極大地占用了記憶體空間。
真正的技術突破,發生在 SQL 解析階段之後的邏輯最佳化環節。Kingbase 的核心思路是:在進入物理執行之前,先在抽象語法樹層面審視這條 SQL 的語意。 
具備高級智慧的資料庫核心在這裡引入了一項堪稱「降維打擊」的最佳化策略:目標欄位被常值固定時的 LIMIT 1 替代法。
它的底層邏輯推理鏈條非常嚴密:
WHERE 條件中明確限制了 a = 1 且 b = 1。a 和 b。(1, 1)。LIMIT 1 的形態,直接繞過底層的去重算子。為了驗證這個理論,我們手動將 SQL 改寫為 LIMIT 1 模式來觀測極限效能:
sql 體驗AI代碼助手 代碼解讀複製代碼-- 驗證 LIMIT 1 帶來的短路效應
EXPLAIN ANALYZE SELECT a, b FROM s1 WHERE a=1 AND b=1 LIMIT 1;

實作見證奇蹟:執行時間從 16.717 毫秒,斷崖式暴降到了驚人的 0.048 毫秒! 原因就在於頂層的 Limit 算子。底層的掃描器只要碰巧掃到了第一條符合要求的資料,就會立刻觸發「短路機制(Short-circuit)」,直接向客戶端返回結果,並強行終止底層後續的無數次掃描。沉重的去重操作被瞬間消解。
單表的常值推導固然驚豔,但真實的企業級應用充斥著複雜的表關聯。在多表 INNER JOIN 的環境下,傳統資料庫的去重機制會引發多大的災難?
我們引入表 s2,建構一個更複雜的關聯去重場景。請注意,接下來的資料會非常震撼。
sql 體驗AI代碼助手 代碼解讀複製代碼-- 複雜多表關聯場景下的去重查詢
EXPLAIN ANALYZE
SELECT s1.a, s2.b
FROM s1
INNER JOIN s2 ON s1.a = s2.b
WHERE s1.a = 5
GROUP BY s1.a, s2.b;

史詩級的效能災難:仔細剖析這條 SQL,存在一個隱蔽的邏輯陷阱:查詢目標欄位是 s1.a 和 s2.b。但在 WHERE 條件中,開發者只寫了 s1.a = 5,並沒有直接說明 s2.b 等於幾。
對於傳統的低階最佳化器來說,它在這裡就停止思考了。從執行計畫中我們可以看到恐怖的一幕:底層的 Nested Loop(巢狀迴圈連接)瘋狂地執行了 2 億次(loops=200000000)!最終導致這條查詢耗時飆升到了令人窒息的 37330.185 毫秒(近 37 秒)!
面對上述災難,具備高階推導能力的現代最佳化器是如何破局的呢?它會在核心中建構一張等值傳遞網路:
s1.a = 5。s1.a = s2.b。s2.b = 5 絕對成立!s1.a 和 s2.b,發現它們的值已經在邏輯上被完全固化為常數!一旦推導成功,高級核心即可觸發等價重寫規則,將外層的去重操作直接替換為 LIMIT 1。我們再次手動模擬核心重寫後的形態,進行效能驗證:
sql 體驗AI代碼助手 代碼解讀複製代碼-- 模擬高階最佳化器透過等值推導重寫後的 SQL
EXPLAIN ANALYZE
SELECT s1.a, s2.b
FROM s1
INNER JOIN s2 ON s1.a = s2.b
WHERE s1.a = 5
LIMIT 1;

執行計畫結果令人振奮:頂層的 Limit 算子如同定海神針。雖然底層掃描定位第一條符合 s1.a=5 的資料花了十幾毫秒,但關鍵在於,那個原本瘋狂循環 2 億次的 Nested Loop,在探測到第一組匹配的資料後被瞬間截斷(loops=1)!
原本耗時近 37 秒 的關聯去重慢查詢,最終耗時僅僅定格在 12.930 毫秒。效能提升了近 3000 倍!
剛才咱們把這些藏在資料庫最底層的執行機制給捋了一遍,其實看完之後,我自己也在琢磨平時大家寫業務程式碼的習慣。也就是說,要是遇到慢查詢的情況,除了砸錢去加伺服器硬體配置這種笨辦法之外,其實利用底層的編譯邏輯去把 SQL 重新處理一遍,才是現在這些底層軟體最關鍵的技術點。
那麼,這些東西對咱們平時做開發的同學來說,其實有這麼幾個挺實在的建議:
LIMIT 1。這種做法,往往僅僅只是多敲了幾個字母,但真的比你完全指望著資料庫底層自己去幫你做分組和去重來得穩當得多。