jsonb 能比資料模型,不能比擴展架構

「PostgreSQL 有 jsonb,那還需要 NoSQL 嗎?」——可以比,但只能比一半。

離開關聯式資料庫通常有兩個理由,它們其實是獨立的:

理由jsonb 解決嗎
(a) 資料沒有固定格式(欄位會變、巢狀、每筆不一樣)✅ 完全解決
(b) 極高資料量,單機撐不住,需要水平擴展❌ 完全沒幫助

jsonb 對應的是 NoSQL 的「資料模型」那一半,不對應「分散式架構」那一半。 MongoDB 的 sharding、DynamoDB 的 partitioning 是營運層的能力,跟「資料長得像文件」無關。

想用 NoSQL 的理由是 schema 會變 → 用 jsonb,不要換資料庫。 理由是 一台機器裝不下/撐不住 → jsonb 一點忙都幫不上。

jsonb 贏在一致性,不是效能

跟「兩套資料庫交錯使用」相比:

CREATE TABLE documents (
  id         bigserial PRIMARY KEY,
  owner_id   bigint REFERENCES users(id),   -- 關聯、外鍵、約束照舊
  updated_at timestamptz NOT NULL,
  content    jsonb NOT NULL                 -- 這格愛怎麼變怎麼變
);

同一列、同一筆交易裡,結構化的部分享有外鍵與 ACID,變動的部分享有 schema-less。跨兩套資料庫寫入時,你得自己處理「SQL 寫成功但 NoSQL 失敗」——那個成本通常沒有被算進去。

實務上會踩到的代價

代價說明
MVCC 寫放大改 jsonb 裡一個小欄位,整份文件會被重寫一次(新列版本)。文件大又改得頻繁 → bloat 與 vacuum 壓力
TOAST超過約 2KB 會被壓縮並搬到行外儲存,讀取多一跳
索引要自己想GIN 能查 containment(@>)但體積大、寫入慢;固定路徑改建表達式索引
CREATE INDEX ON documents ((content->>'status'));

這裡有個陷阱:索引必須跟 WHERE 裡的表達式長得一模一樣,否則用不到——見 把欄位包進函數,WHERE 就用不到那個欄位的索引。

預設值

先用 jsonb,等你能明確講出「是上面哪一條讓我非換不可」再換。 這跟 反正規化要排在索引與物化視圖後面 的精神一致——換資料庫是梯子的最後一階,不是第一階。

型別本身的細節見 什麼是 jsonb。