建索引的代價是毫秒,收益可能是秒

建索引是拿寫入成本與儲存空間換讀取速度(見 索引是拿寫入換查詢,寫多讀少的表加索引是純虧)。那篇講的是這筆交易的形狀;這篇講怎麼判斷這筆交易划不划算。 四個維度。

1. 讀寫比例

Web / API 系統大多是讀多寫少,常見 9:1 或 8:2。如果一張表 90% 是 SELECT、10% 是 INSERT/UPDATE,替查詢省下的時間遠遠壓倒寫入多出來的那幾毫秒。

例外:高頻寫入的 log 表、IoT 秒級上報表(寫入佔 95% 以上),建索引要極度謹慎。

2. 兩邊根本不在同一個數量級

付出(寫入變慢)INSERT 多維護一棵 B-Tree 約 0.1 ~ 1 ms
UPDATE 只有改到索引包含的欄位時才要更新索引;只改無關欄位時 PostgreSQL 的 **HOT(Heap-Only Tuple)**機制可能連索引都不用碰(這句把 HOT 當成常態,有爭議 → PG 的 HOT 什麼時候會失效?)
獲得(讀取變快)查詢從 14,329 ms 降到 2 ms,單次省下 14 秒的 CPU 與磁碟 I/O

拿寫入增加 1 ms 去換單次讀取省下 14,000 ms——就算這張表讀寫比是 1:1,也是壓倒性划算的交易。

3. 慢查詢會霸佔連線,這才是非建不可的理由

這一點決定「該不該優先處理」,而不只是「划不划算」:

一條 SQL 跑 14 秒
  → 它佔住一個連線整整 14 秒,而且期間 CPU 全力運轉
  → 同時有 10 個人或報表在查 → 吃掉 10 個連線
  → 後面進來的請求開始排隊
  → 連線池耗盡(Connection Pool Exhaustion)
  → 整個系統癱瘓

PostgreSQL 的連線數是有限的(例如上限 100~200)。所以:

任何單次執行超過數秒的高頻或常態查詢,通常都必須優先解決,否則會拖垮整座資料庫的寫入與讀取。

一條慢查詢的傷害不會停在它自己身上。

4. 決策檢查清單

評估問題傾向「建」傾向「不建/另尋他法」
讀取耗時多長?數百毫秒到數秒原本就只要 5~10 ms
寫入頻率?正常業務寫入、批次寫入、讀多寫少每秒數萬筆的極高頻純寫入
索引欄位更新頻率?識別碼、年月、狀態這類很少被 UPDATE 的欄位數值每秒都在異動
這張表已有幾個索引?只有主鍵或 1~2 個(維護成本低)已有 15 個以上(先清理廢索引)

和另外兩條判準的關係

這四個維度回答的是「值不值得」。還有兩個前置問題要先過:

確認要建之後,欄位怎麼選見 複合索引的欄位 = Index Cond 的欄位 + Filter 裡的等值欄位。