具代表性的面試主題

如何在線安全地建立或重建 PostgreSQL 索引?

後端困難
OfferCC 編輯團隊發佈 更新

題幹

一張數十億行的 PostgreSQL 表需要新增索引或重建膨脹索引,但業務不能停機。請設計執行步驟、失敗復原與驗證指標。

1. 題目

生產表持續接收訂單寫入,查詢團隊希望新增複合索引;另一張表的索引膨脹,需要重建。表規模很大,發布窗口只有低峰期,且不能阻塞一般讀寫。請給出可回滾、可觀測的線上方案。

2. 約束與澄清

  • 先確認 PostgreSQL 版本、資料表與索引類型、主從拓撲、磁碟餘量及寫入峰值。
  • 區分 CREATE INDEX、CREATE INDEX CONCURRENTLY、REINDEX CONCURRENTLY 的適用場景。
  • 並行建立可減少寫入鎖影響,但會多次掃描資料表、佔用 CPU/IO,且不能放在交易區塊中。
  • 先定義可接受的建立時間、鎖等待、延遲與失敗後的清理窗口。

3. 核心思路

一般建立索引可能阻塞寫入;並行建立允許持續插入、更新與刪除,但需要更長時間與更多資源。應先在影子環境用真實規模估算,生產執行時設定 lock_timeout、statement_timeout 與資源監控。索引完成後還要確認規劃器選擇、回滾路徑與副本一致性,不能把指令成功當成業務成功。

4. 參考流程

text
preflight:
  verify_version_replicas_disk_and_query_shape()
  estimate_scan_cost_on_shadow_copy()
  reserve_maintenance_window_and_abort_thresholds()

build:
  set lock_timeout = short
  set statement_timeout = bounded
  CREATE INDEX CONCURRENTLY idx_orders_customer_time
    ON orders (customer_id, created_at DESC)

verify:
  inspect_index_state_and_size()
  EXPLAIN (ANALYZE, BUFFERS) representative_queries()
  compare_write_latency_replica_lag_and_error_rate()

重建時優先使用 REINDEX CONCURRENTLY;若失敗留下無效的暫存索引,先依文件識別並清理,再重新嘗試。部署腳本要保證命名、冪等與告警可追蹤,不能把並行 DDL 藏在一般交易遷移裡。

5. 失敗場景與取捨

並行建立可能因長交易、衝突快照或磁碟不足失敗;失敗物件可能保持無效狀態,繼續佔用空間。建立期間 CPU、IO 與 WAL 增長會拖慢業務並拉大複製延遲,因此要限速或暫停。若無法接受建立成本,可以先優化查詢、分區或使用線上遷移工具,但工具仍需驗證觸發器、回填、切換與回滾行為。

6. 驗證與觀測

  • 記錄索引狀態、大小、建立耗時、鎖等待、WAL、CPU/IO 與副本延遲。
  • 對代表性查詢比較執行計畫、掃描行數、p95/p99 延遲與寫入吞吐。
  • 檢查長交易、無效索引、重複索引及約束依賴。
  • 觀察多個完整業務高峰後再刪除舊索引,並保留復原腳本。

7. 常見誤區

  • 以為 CONCURRENTLY 完全不拿鎖,忽略短暫鎖等待與資源競爭。
  • 把 CREATE INDEX CONCURRENTLY 放進交易區塊,導致指令直接失敗。
  • 只看建立索引指令成功,不檢查無效索引、複製延遲與實際計畫。
  • 沒有磁碟、WAL 與長交易預算就直接對超大表重建。

8. 面試評分點

能區分並行 DDL 語義

應說明一般與並行建立、重建索引的鎖、掃描次數、交易限制與資源代價。

能規劃生產前置檢查

應檢查版本、磁碟、長交易、複製拓撲、查詢形狀,並先用接近真實規模的資料估算。

能設計失敗復原

應處理無效索引、逾時、磁碟不足與複製落後,說明清理、重試與回滾步驟。

能用業務指標驗證

應比較執行計畫、p95/p99、寫入延遲、WAL、鎖等待與副本延遲,而不是只看 DDL 回傳碼。

公開來源

同類題目

資源

產品比較

每份比較均依官方資料整理,並標示複核日期。

查看完整比較