電商系統常見需求:依數百至數千個分散 ID 批次查詢商品屬性。網路上建議五花八門(臨時表 JOIN、分批查詢、UNION ALL 等),本文在 PostgreSQL 9.4 實測環境 (50 萬筆測試資料、唯一 B-tree 索引) 驗證各方案真實效能。
CREATE TABLE t9 (
c1 INTEGER PRIMARY KEY,
c2 CHAR(100),
c3 CHAR(200)
);
CREATE UNIQUE INDEX i1 ON t9 (c1);
-- 產生 50 萬筆測試資料
INSERT INTO t9
SELECT generate_series(1000, 500000, 1), repeat('a', 90), repeat('b', 180);
產生 100 / 1,000 / 10,000 個隨機 ID 組成 `IN` 清單:
| IN 清單筆數 | 執行時間 | 執行計畫 |
|---|---|---|
| 100 | 2.88 ms | Index Scan |
| 1,000 | 11.97 ms | Index Scan |
| 10,000 | 355.69 ms | Index Scan → Bitmap Heap Scan |
CREATE TEMP TABLE t_tmp (id INT);
INSERT INTO t_tmp VALUES (...); -- 同樣 100/1,000/10,000 筆
SELECT t9.* FROM t9 JOIN t_tmp ON t9.c1 = t_tmp.id;
| 筆數 | 建表+寫入 | JOIN 查詢 | 總計 | 執行計畫 |
|---|---|---|---|---|
| 100 | 3.05 ms | 1.91 ms | ~5 ms | Nested Loop |
| 1,000 | 3.44 ms | 8.78 ms | ~12 ms | Nested Loop |
| 10,000 | 3.31 ms | 546 ms | ~550 ms | Merge Join |
-- VALUES 寫法 (標準 SQL)
SELECT t9.* FROM t9
JOIN (VALUES (494613), (575087), ...) AS v(id) ON t9.c1 = v.id;
-- UNNEST 陣列參數 (需驅動程式支援)
SELECT * FROM t9 WHERE c1 = ANY($1); -- $1 為 integer[] 參數
核心心法: 信任資料庫優化器,優先用最直觀的 `IN` 清單;只有當參數量級確實超過優化器甜蜜點 (通常數千~萬筆) 時,才引入陣列參數或臨時表,並務必實測驗證。