Back to Blogs
postgresql

PostgreSQL vs MySQL

從架構、MVCC、索引、鎖、複製、型態系統等面向,全面比較 PostgreSQL 與 MySQL 的設計差異與適用場景

Aaron

兩者都是成熟的開源關聯式資料庫,但設計哲學截然不同:MySQL 追求簡單高效、PostgreSQL 追求正確完整

架構

面向PostgreSQLMySQL (InnoDB)
程序模型Multi-process(fork per conn)Multi-thread
連線開銷重(需連線池)
資料頁大小8 KB16 KB
記憶體快取Shared Buffers + OS Page CacheBuffer Pool(自管理)
Storage Engine只有一種(heap + WAL)可插拔(InnoDB 為主)
系統目錄SQL 標準 information_schema + 自有 pg_cataloginformation_schema + mysql schema

PostgreSQL 的 multi-process 模型穩定性更好(一個 backend crash 不影響其他),但連線開銷大,生產環境必須搭配 PgBouncer。MySQL 的 thread 模型天生適合高連線數場景。

MVCC

這是兩者最大的架構差異

面向PostgreSQLMySQL (InnoDB)
舊版本存放同一張表(heap tuple)Undo Log(獨立空間)
UPDATE 行為插入新 tuple + 標記舊 tuple xmax原地修改 + 舊值存 Undo Log
清理VACUUM(必須、需調校)Purge Thread(自動、免維護)
表膨脹會(dead tuple 累積)不會(Undo 獨立空間)
Crash 回滾不需要(標記 aborted)需要 Undo Log 逆向回復
Transaction ID32-bit,需 freeze 防 wraparound隱藏欄位,無 wraparound 風險

PostgreSQL 的 MVCC 更簡單(不需要 undo log),但維運成本更高(VACUUM tuning 是必修課)。MySQL 的 MVCC 維運幾乎免費,但 Undo Log + 兩階段提交的架構更複雜。

日誌系統

面向PostgreSQLMySQL
Crash RecoveryWALRedo Log
Replication同一套 WALBinlog(獨立於 Redo Log)
日誌套數一套兩套(需兩階段提交保一致)
邏輯複製Logical Decoding(解碼 WAL)Binlog(天生邏輯)
PITRWAL ArchiveBinlog

PostgreSQL 一套 WAL 打天下,架構乾淨;MySQL 兩套日誌職責分明但需要兩階段提交保持一致。

交易隔離

面向PostgreSQLMySQL (InnoDB)
預設隔離等級Read CommittedRepeatable Read
RR 實作Snapshot IsolationMVCC + Next-Key Lock
幻讀防護(RR)SI 天生防(snapshot 機制)快照讀防、當前讀靠 Next-Key Lock
寫衝突(RR)報錯(first-updater-wins)等鎖(在最新版本上修改)
SerializableSSI(樂觀,高併發)所有 SELECT 加 S Lock(悲觀,低併發)
Gap Lock
死鎖風險較低較高(gap lock 交叉)

PostgreSQL 在高隔離等級下的併發度明顯優於 MySQL,特別是 Serializable(SSI vs 全鎖)。但 MySQL 的 RR 對應用層更「寬容」——寫衝突等鎖而非報錯,不需要 retry 邏輯。

索引

索引類型PostgreSQLMySQL (InnoDB)
B-Tree✓(B+ Tree)
Hash✓(Adaptive Hash,自動)
GIN(倒排)
GiST(空間)✗(靠 R-Tree)
BRIN
Full-Text✓(GIN + tsvector)✓(InnoDB FTS)
Partial
Expression✓(8.0+)
Covering✓(INCLUDE)✓(天生在 Secondary Index)

PostgreSQL 的索引種類遠多於 MySQL,特別是 GIN(JSONB、全文搜尋)和 BRIN(大表時序)這兩個在 MySQL 中沒有對應物。

但 MySQL 的 Clustered Index 讓主鍵查詢天生不需要回表(資料就在索引裡),這點 PostgreSQL 做不到——所有索引都是 secondary,都需要回 heap。

面向PostgreSQLMySQL (InnoDB)
行鎖實作標記在 tuple header鎖在索引記錄上
Gap Lock有(Next-Key Lock)
行鎖粒度4 種(FOR KEY SHARE/SHARE/NO KEY UPDATE/UPDATE)2 種(S/X)
Advisory Lock強(bigint key、xact-level)弱(字串 key、session-only)
DDL 風險高(AccessExclusiveLock 阻塞一切)中(Online DDL 較成熟)

PostgreSQL 的 FOR NO KEY UPDATE 讓外鍵檢查不阻塞普通 UPDATE,是比 MySQL 更精細的設計。但 MySQL 的 Online DDL 比 PostgreSQL 成熟(PostgreSQL 做 DDL 經常需要 pg_repack 或 lock_timeout 技巧)。

型態系統

PostgreSQL 的型態系統遠比 MySQL 豐富:

型態PostgreSQLMySQL
JSONjson + jsonbjson(無 binary)
Array✓(原生)
Range✓(int4range 等)
Enum✓(可新增值)✓(改定義需 ALTER)
Composite✓(自訂型態)
Domain✓(帶約束的型態)
UUID✓(原生型態)✓(8.0 UUID 函數)
Networkinet cidr macaddr
Geometric✓(原生)✗(需 spatial extension)

JSONB 是 PostgreSQL 的殺手功能之一——binary 格式、可建 GIN 索引、支援豐富的操作符,效能遠勝 MySQL 的 JSON 型態。

SQL 功能

功能PostgreSQLMySQL
Window Function✓(完整支援)✓(8.0+,較晚支援)
CTE✓(含 recursive + writable CTE)✓(8.0+,不支援 writable)
LATERAL JOIN✓(8.0.14+)
UPSERTINSERT ... ON CONFLICTINSERT ... ON DUPLICATE KEY
RETURNING
Generate Series✓(8.0.33+ recursive CTE)
Materialized View
Foreign Data Wrapper✓(查詢外部資料來源)

RETURNING 是 PostgreSQL 的一大便利——INSERT/UPDATE/DELETE 後直接回傳修改的行,不需要額外 SELECT:

INSERT INTO orders (customer_id, amount)
VALUES (1, 500)
RETURNING id, created_at;
-- 直接拿到自增 ID 和預設值,不需要 LAST_INSERT_ID()

擴展性

PostgreSQL 的擴展機制是另一個殺手功能:

Extension用途
PostGIS地理空間(業界標準)
pg_trgm模糊搜尋(similarity)
pgvector向量搜尋(AI embedding)
TimescaleDB時序資料庫
Citus分散式 / sharding
pg_stat_statementsSQL 效能分析

MySQL 沒有等價的擴展機制。PostGIS 讓 PostgreSQL 在地理空間領域幾乎沒有對手;pgvector 讓它在 AI 應用中也很有競爭力。

適用場景

選 PostgreSQL 的理由

  • 資料型態複雜(JSONB、array、range、geometry)
  • 需要進階 SQL(CTE、window function、LATERAL)
  • 需要 GIN/GiST/BRIN 索引
  • 需要 PostGIS(地理空間)或 pgvector(向量搜尋)
  • 需要高隔離等級的高併發(SSI)
  • 對 SQL 標準合規有要求

選 MySQL 的理由

  • 簡單的 OLTP workload(CRUD 為主)
  • 超高連線數(不想管連線池)
  • 不想花時間調 VACUUM
  • 團隊更熟悉 MySQL 生態
  • 需要成熟的 Online DDL
  • 讀多寫少、需要大量 read replica

兩者都行的場景

  • 一般 web 應用的後端資料庫
  • 微服務架構中的服務資料庫
  • 中等規模的 OLTP

一句話總結

MySQL 是一把好用的螺絲起子——簡單、可靠、上手快。PostgreSQL 是一整套瑞士刀——功能強大、面面俱到,但需要更多學習和維運投入。選擇取決於你的場景複雜度和團隊能力。