Java 開發者習慣命令式、物件導向思維,但 SQL 是基於集合論的宣告式語言。寫好 SQL 需要跳脫「逐行處理」的習慣,轉而思考「集合運算」。

錯誤:以為 NULL = NULL 為真,或誤解 NOT IN 含 NULL 時的行為。
對策:時刻記住 IS NULL/IS NOT NULL,使用 COALESCE 處理,避免在 NOT IN 子查詢中出現 NULL。
錯誤:將大量資料拉到 Java 中用迴圈計算,忽略資料庫的 OLAP/視窗函數能力。
對策:下推運算到資料庫。使用視窗函數、MODEL 子句等進階 SQL 功能,只傳回結果集,減少網路傳輸。
錯誤:預設用 UNION 去重,導致大結果集排序比較,效能低落。
對策:除非業務確實需要去重,否則一律用 UNION ALL。
錯誤:在 Java 端分頁,傳輸百萬行資料。
對策:使用資料庫原生分頁:LIMIT/OFFSET、OFFSET/FETCH、ROW_NUMBER() 等。
錯誤:分別查詢兩張表,在 Java Map 中 JOIN。
對策:單一 SQL 完成連接,利用資料庫優化器的 MERGE/HASH JOIN 效能遠超應用層。
錯誤:連接條件不全產生重複,用 DISTINCT 強行去重。
對策:檢查 JOIN 條件,修正笛卡爾積根因,避免排序去重的效能代價。
錯誤:用 SELECT ... FOR UPDATE + INSERT/UPDATE 實現上鎖邏輯。
對策:使用標準 MERGE 或 MySQL ON DUPLICATE KEY UPDATE,原子性更強、並發更好。
錯誤:子查詢 GROUP BY 再 JOIN 回主查詢。
對策:使用 OVER(PARTITION BY ...) 視窗函數,減少子查詢,提升可讀度與效能。
錯誤:認為 SQL 排序慢或不支援複雜邏輯(如 CASE WHEN 排序)。
對策:ORDER BY CASE WHEN ... THEN ... END 完全在資料庫層完成。
錯誤:迴圈建立 PreparedStatement 逐筆插入。
對策:批次插入:單一 SQL + 多組綁定參數,addBatch()/executeBatch(),適時提交控制 UNDO 日誌大小。
「讓資料庫做資料庫擅長的事:集合運算、連接、聚合、排序、分頁。應用層只負責業務流程與結果呈現。」