B03 · 資料持久化 詳細 ROADMAP
計畫文件,不會被 Quartz 渲染。
回主 roadmap → backend/ROADMAP.md
既有 database/ 系列 → database/index.md
章節目標
資料庫是後端最容易「看起來簡單實際超難」的主題。本章的定位:從後端工程師視角切入——不是 DBA 的視角(例如不講 storage engine 細節)、也不是純 SQL 教學(那在 database/ 系列)、而是「寫後端時要知道的資料庫知識」:連線池 / 交易隔離 / 索引策略 / ORM 取捨 / 遷移 / 分區。
🌱 基本介紹
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 01 | 後端視角的資料庫 | 01-what-is-backend-db | 🌱 | 後端寫 DB 的 3 個關卡:正確性(交易)/ 效能(索引、池)/ 演進(migration) |
❓ 為什麼需要
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 02 | 為什麼不懂 isolation level 會資料壞 | 02-why-isolation-level-matters | 🌱 | Read phenomena(dirty / non-repeatable / phantom)實際案例、預設 isolation level 坑(MySQL REPEATABLE READ vs PG READ COMMITTED) |
| 03 | 為什麼 ORM 會害你 | 03-why-orm-hurts | 🌱 | N+1 問題、lazy load 失控、SELECT * 習慣、不知道真實 SQL、到 scale 才爆 |
| 04 | 為什麼一定要懂 B+ tree | 04-why-btree-matters | 🌱 | 理解索引設計 / 複合索引順序 / LIKE ‘xxx%’ 可用索引、為什麼 UUID v4 當 PK 糟糕 |
| 05 | 為什麼連線池大小不是越大越好 | 05-why-pool-size | 🌱 | DB 連線是昂貴資源、connection = 一個 backend process(PG)、pool 過大壓死 DB |
🕰️ 演進
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 06 | 關聯式 DB 演進 | 06-rdbms-evolution | 🌱 | 1970 Codd 關聯模型 → SQL 標準 → MySQL / PG 興起 → NoSQL 回潮 → NewSQL(Spanner / CockroachDB)→ Vector DB 時代 |
| 07 | ORM 演進史 | 07-orm-evolution | 🌱 | ActiveRecord(Rails)→ Hibernate → Django ORM → SQLAlchemy → Prisma / Drizzle / TypeORM;current state |
| 08 | Migration 工具演進 | 08-migration-evolution | 🌱 | 手動 SQL → Flyway / Liquibase → framework 內建(Rails / Django / Laravel)→ Atlas / goose / sqlx-migrate |
🧠 知識型
F03-A SQL 基礎與進階
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 09 | SQL 基礎 | ⛔️ database/index | 🌿 | 跨系列 |
| 10 | Window Function | 10-window-function | 🌱 | ROW_NUMBER / RANK / LAG / LEAD 實戰;為什麼 self-join 之前這是噩夢 |
| 11 | CTE 與 Recursive CTE | 11-cte-recursive | 🌱 | WITH 寫可讀複雜 query、tree-like 資料用 recursive CTE |
| 12 | JSON / JSONB 欄位 | 12-json-columns | 🌱 | PG JSONB / MySQL JSON、索引(GIN)、什麼時候該用什麼時候不該用 |
F03-B DB 引擎與選型
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 13 | PostgreSQL 核心 | ⛔️ infra/11-database-postgresql | 🌿 | 跨系列 |
| 14 | PostgreSQL 進階 | ⛔️ infra/13-postgresql-advanced | 🌿 | 跨系列 |
| 15 | PG vs MySQL | ⛔️ micro-service/17-db-pg-vs-mysql / 31-pg-vs-mysql-deep-dive | 🌿 | 跨系列 |
| 16 | NoSQL 分類 | 16-nosql-taxonomy | 🌱 | KV(Redis)/ Document(Mongo)/ Column(Cassandra)/ Graph(Neo4j)、適用場景 |
| 17 | NewSQL(Spanner / CockroachDB / TiDB) | 17-newsql | 🌱 | 分散式 ACID、shard auto-management、何時值得 |
| 18 | Vector DB(pgvector / Pinecone / Qdrant) | 18-vector-db | 🌱 | 2026 AI 時代必要、相似度查詢、跟 RAG 整合 |
F03-C Transaction 與正確性
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 19 | ACID 逐字拆 | 19-acid | 🌱 | Atomicity / Consistency / Isolation / Durability 各自怎麼實作、代價 |
| 20 | Isolation Level | 20-isolation-level | 🌱 | Read Uncommitted / Committed / Repeatable Read / Serializable、對應 read phenomena、MySQL vs PG 預設差異 |
| 21 | MVCC 機制 | 21-mvcc | 🌱 | 為什麼 PG / MySQL InnoDB 用 MVCC、snapshot isolation、vacuum 代價 |
| 22 | 悲觀鎖 vs 樂觀鎖 | ⛔️ micro-service/60-optimistic-pessimistic-locking | 🌿 | 跨系列 |
| 22-2 | Race Condition 與分散式鎖 | ⛔️ micro-service/59-race-condition-distributed-lock | 🌿 | 跨系列 |
| 23 | 死鎖預防與診斷 | 23-deadlock | 🌱 | 怎麼產生、怎麼看(PG pg_locks / MySQL SHOW ENGINE INNODB STATUS)、lock order 策略 |
F03-D 索引與查詢規劃
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 24 | 索引與查詢規劃 | ⛔️ micro-service/18-db-bulk-and-index | 🌿 | 跨系列 |
| 25 | B+ Tree 詳細 | 25-btree-deep | 🌱 | 節點結構、leaf node 串接、為什麼 range scan 快、為什麼 UUID v4 亂序 PK 差 |
| 26 | 複合索引策略 | 26-composite-index-strategy | 🌱 | 最左前綴原則、覆蓋索引、order by 跟 where 怎麼配合 |
| 27 | EXPLAIN / EXPLAIN ANALYZE 讀法 | 27-explain-analyze | 🌱 | Seq Scan / Index Scan / Bitmap / Nested Loop / Hash Join / Merge Join、cost 怎麼看 |
F03-E ORM 與 Data Access Layer
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 28 | ORM vs Query Builder vs Raw SQL | 28-orm-vs-query-builder-vs-raw | 🌱 | 三種分層的 trade-off;哪種場景選哪種 |
| 29 | N+1 問題深入 | 29-n-plus-1 | 🌱 | 怎麼產生、怎麼偵測、eager load / data loader / batching 對策 |
| 30 | Repository Pattern | 30-repository-pattern | 🌱 | 從 Active Record 到 Repository、跟 DDD 整合、泛型 BaseRepository(proto shared 有實作 ⛔️ 見 B07) |
F03-F 連線池與效能
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 31 | 連線池原理 | ⛔️ micro-service/19-db-pool-and-infra | 🌿 | 跨系列 |
| 32 | PgBouncer / ProxySQL | 32-connection-proxy | 🌱 | 為什麼需要、transaction / session / statement pooling mode、Serverless 場景必要性 |
| 33 | Prepared Statement | 33-prepared-statement | 🌱 | server-side parsing cache、跟 connection pool 的互動(同 connection 才 reuse) |
| 33-2 | DB 批次處理極限狀態 | 33-2-db-batch-limit | 🌱 | Bulk insert 數萬 / 數百萬筆的瓶頸:記憶體爆、transaction log 爆、lock contention、timeout;chunk 策略(how large is safe)、streaming query(server-side cursor)、COPY(PG)vs 單筆 INSERT;跟 B19 #22 壓測案例連動 |
F03-G Migration 與演進
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 34 | Migration 基礎 | 34-migration-basics | 🌱 | up / down、版本控制、團隊協作(衝突處理) |
| 35 | Zero-downtime Migration | 35-zero-downtime-migration | 🌱 | expand-contract pattern、column add/drop 分三步、rolling deploy 配合 |
| 36 | 資料遷移 vs schema 遷移 | ⛔️ micro-service/32-pg-migration-guide | 🌿 | 跨系列 |
F03-H 分區與 Sharding
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 37 | Partitioning | 37-partitioning | 🌱 | PG declarative partition、MySQL partition;Range / List / Hash 策略 |
| 38 | Sharding | 38-sharding | 🌱 | 何時該 shard、shard key 選擇、跨 shard 交易地獄 |
| 39 | Read Replica | 39-read-replica | 🌱 | Replication 模式(async / sync)、replication lag 監控、讀寫分離的坑 |
| 39-2 | 讀寫分離實戰 | ⛔️ micro-service/61-db-read-write-splitting | 🌿 | 跨系列 |
F03-I 搜尋引擎
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 40 | Elasticsearch / OpenSearch | ⛔️ infra/14-elasticsearch-deep-dive | 🌿 | 跨系列 |
| 41 | PG Full Text Search | 41-pg-fts | 🌱 | tsvector / tsquery、GIN 索引、什麼時候 PG FTS 夠用、什麼時候該上 ES |
| 41-2 | Search:MySQL / PG / ELK 選型 | ⛔️ micro-service/56-search-mysql-pg-elk | 🌿 | 跨系列 |
| 41-3 | Recommendation with ELK | ⛔️ micro-service/57-recommendation-with-elk | 🌿 | 跨系列 |
| 41-4 | DB 選型總結 | ⛔️ micro-service/65-conclusion-db | 🌿 | 跨系列 |
F03-J 微服務化的 DB 策略
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 41-5 | Database-per-service vs Shared DB | 41-5-db-per-service | 🌱 | 兩種模式的 trade-off;DB-per-service 是 textbook 答案但實戰有代價;什麼規模值得轉換 |
| 41-6 | Shared Schema → 分 DB 的遷移路徑 | 41-6-shared-to-split-db | 🌱 | Expand-contract for DB schema;先分 schema 再分 instance;foreign key 跨 DB 如何處理 |
| 41-7 | Master Data 管理 | 41-7-master-data-management | 🌱 | 哪個 service 是某資料的 source of truth;跨服務資料一致性;authoritative service 設計 |
| 41-8 | Data Duplication 策略 | 41-8-data-duplication | 🌱 | User 資料在 auth / profile / order 各存一份的 trade-off;同步機制;eventual consistency 接受度 |
| 41-9 | CDC(Change Data Capture) | 41-9-cdc | 🌱 | Debezium / PG logical replication;DB 變更推送到 Kafka;跟 Outbox pattern 的差異與互補 |
| 41-10 | Event Sourcing 跨服務歷史 | 41-10-event-sourcing-cross-service | 🌱 | 事件當真相來源;重放建 state;跨服務查歷史不用 join |
| 41-11 | Multi-tenancy DB 策略 | 41-11-multi-tenancy-db | 🌱 | Shared DB + tenant_id / Separate schema / Separate DB 三種模式;跨租戶資料洩漏風險;migration 成本 |
🔧 小實作注意事項
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 42 | 壓測前後的 query 改造案例 | ⛔️ micro-service/18-db-bulk-and-index / 19-db-pool-and-infra | 🌿 | 跨系列 |
| 43 | 本機跑 PG + Mongo + Redis(Docker Compose) | 43-local-db-stack | 🌱 | 開發用 stack、volumes、seed data、reset workflow |
| 44 | DB 連線池參數怎麼調 | 44-pool-sizing | 🌱 | 公式:threads × connections ≤ pool;實際案例 |
💣 Anti-pattern
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 45 | DB Anti-patterns | 45-db-antipatterns | 🌱 | N+1、SELECT *、UUID v4 當 PK、index 不夠或太多、nullable foreign key 濫用、用 DATETIME 不用 TIMESTAMPTZ、在 application 層做 JOIN(應該在 DB)、pool size 訂 200+、migration 沒 down、schema 跟 data migration 混 |
🧰 對應檢查工具
| # | 主題 | Slug | Stage | 大綱 |
|---|
| 46 | 資料庫工具 | 46-db-tooling | 🌱 | pgAdmin / DBeaver、pt-query-digest(MySQL)、pganalyze / pg_stat_statements、sqlfluff(lint)、Atlas(migration)、schemaspy(文件) |
📎 補充
| # | 主題 | Slug | Stage | 大綱 |
|---|
| S01 | 為什麼 UUID v7 適合當 PK | s01-uuid-v7 | 🌱 | timestamp-based、index-friendly、2024 RFC 9562 標準化 |
| S02 | Soft Delete 的坑 | s02-soft-delete | 🌱 | deleted_at pattern、unique constraint 失效、報表雙重邏輯、何時該 hard delete |
| S03 | Time-series DB(TimescaleDB / InfluxDB) | s03-timeseries-db | 🌱 | 為什麼時序資料不適合一般 RDBMS、何時值得上 TSDB |
章節進度統計
- 知識主題:46 + 3 補充 = 49 項
- 🌿 growing:6(跨系列)
- 🌱 seed:43
跨系列連結
- →
database/index(SQL 基礎系列)
- →
infra/ 11、13、14(PG / PG Advanced / ES)
- →
micro-service/ 17–19、31–32、56–57、59–61、65(PG vs MySQL、bulk、pool、migration、search、lock、read-write split、conclusion)
- →
backend/cache/ B13(DB cache 層)
- →
backend/conventions/ B07 Repository(proto BaseRepository 實作)
- →
backend/stress-testing/ B19(壓測暴露 DB 瓶頸)
- →
standards/04-good-database-design