結論先講

PostgreSQL 不是贏在某一個功能,而是贏在「你以為需要另一個資料庫的時候,PG 已經有了」。 JSONB 讓你少裝 MongoDB,pgvector 讓你少裝 Pinecone,pg_trgm 讓你少裝 Elasticsearch,PostGIS 讓你少裝任何 GIS 方案。一個資料庫搞定八成需求,運維少一半。

2026 年的 Stack Overflow 調查、Hacker News 討論、各大框架的預設設定,PostgreSQL 已經是事實上的標準。不是因為炒作,是因為它真的夠好。


PostgreSQL vs MySQL:功能對比

先上硬數據。以下比較的是 MySQL 8.0+ 和 PostgreSQL 16+:

功能PostgreSQLMySQL 8.0+
嚴格型別天生嚴格,不允許隱式轉換需設定 STRICT_TRANS_TABLES
JSONB原生二進位 JSON,GIN 索引JSON 型別,需 generated column 做索引
Array 型別原生支援不支援
CTE (WITH)8.1+(2005 年)8.0+(2018 年)
Window Functions8.4+(2009 年)8.0+(2018 年)
全文搜尋內建 tsvector/tsquery + 多語言內建但功能較弱
GIS 地理資料PostGIS 擴展(業界標準)有基本支援,遠不如 PostGIS
UPSERTON CONFLICT DO UPDATEON DUPLICATE KEY UPDATE
ENUM原生型別,可修改需 ALTER TABLE 重建
Partial Index支援不支援
Expression Index支援8.0+ functional index
LISTEN/NOTIFY原生即時通知不支援(需 polling)
擴展系統極強(PostGIS, pgvector, 200+)有限
預設隔離等級Read Committed(MVCC)Repeatable Read(InnoDB)
序列 (Sequence)原生 SEQUENCEAUTO_INCREMENT

MySQL 8.0 追上了 CTE 和 Window Functions,但 PG 的領先在於擴展生態系——下一節是重點。


擴展生態:PostgreSQL 的殺手鐧

PostGIS — 當你需要地理資料

全世界最強的開源 GIS 資料庫。Google Maps、Uber、Airbnb 的地理查詢都靠它。

-- 找出台北車站 1 公里內的餐廳
SELECT name, ST_Distance(
  location,
  ST_SetSRID(ST_MakePoint(121.5170, 25.0478), 4326)::geography
) AS distance_meters
FROM restaurants
WHERE ST_DWithin(
  location,
  ST_SetSRID(ST_MakePoint(121.5170, 25.0478), 4326)::geography,
  1000  -- 1000 公尺
)
ORDER BY distance_meters;

你在 MySQL 裡要做同樣的事情,要不就用精度差的 ST_Distance_Sphere,要不就自己寫 Haversine 公式。PostGIS 直接給你測地線精確距離。

pgvector — 當你不需要 Pinecone

AI 時代最需要的擴展。讓 PostgreSQL 變成向量資料庫。

-- 安裝擴展
CREATE EXTENSION vector;
 
-- 建立帶向量欄位的表
CREATE TABLE documents (
  id SERIAL PRIMARY KEY,
  content TEXT,
  embedding vector(1536)  -- OpenAI text-embedding-3-small 維度
);
 
-- 建立 HNSW 索引(效能關鍵)
CREATE INDEX ON documents
  USING hnsw (embedding vector_cosine_ops);
 
-- 語義搜尋:找最接近的 5 筆
SELECT content, embedding <=> $1 AS distance
FROM documents
ORDER BY embedding <=> $1
LIMIT 5;

什麼時候 pgvector 就夠?

  • 向量數量在百萬級以下
  • 你的主資料庫已經是 PG
  • 你不想多維護一個服務

什麼時候需要專用 Vector DB?

  • 向量數量超過千萬
  • 需要即時索引更新 + 超低延遲
  • 需要多租戶隔離

pg_trgm — 當你不需要 Elasticsearch

三字母組 (trigram) 模糊搜尋。小到中型的搜尋場景,這個就夠了。

-- 安裝擴展
CREATE EXTENSION pg_trgm;
 
-- 建立 GIN 索引
CREATE INDEX idx_products_name_trgm
  ON products USING gin (name gin_trgm_ops);
 
-- 模糊搜尋 + 相似度排序
SELECT name, similarity(name, '機械健盤') AS sim
FROM products
WHERE name % '機械健盤'  -- % 是相似度運算子
ORDER BY sim DESC
LIMIT 10;
-- 即使打錯字(健→鍵),也能找到「機械鍵盤」

對於部落格搜尋、產品搜尋、用戶名搜尋,pg_trgm 加上內建的 tsvector 全文搜尋通常就夠了。不需要架一台 Elasticsearch。

TimescaleDB — 當你不需要 InfluxDB

把 PG 變成時序資料庫。

-- 建立 hypertable(自動依時間分割)
SELECT create_hypertable('sensor_data', 'time');
 
-- 連續聚合(自動維護的 materialized view)
CREATE MATERIALIZED VIEW hourly_avg
WITH (timescaledb.continuous) AS
SELECT time_bucket('1 hour', time) AS hour,
       sensor_id,
       avg(temperature) AS avg_temp
FROM sensor_data
GROUP BY hour, sensor_id;

好處:你不用學 InfluxDB 的 Flux 語言,直接用 SQL。壞處:超大規模(每秒百萬寫入)時,專用時序資料庫還是更快。


JSONB:你可能不需要 MongoDB

這是很多人轉 PG 的關鍵原因。JSONB 不是把 JSON 當字串存——它是解析成二進位格式,可以建索引、可以查詢、可以部分更新。

-- 存入半結構化資料
INSERT INTO products (data) VALUES ('{
  "name": "機械鍵盤",
  "price": 3500,
  "specs": {
    "switches": "Cherry MX Brown",
    "layout": "75%",
    "features": ["RGB", "熱插拔", "PBT鍵帽"]
  }
}'::jsonb);
 
-- 查詢巢狀欄位
SELECT data->>'name' AS name, data->'specs'->>'layout' AS layout
FROM products
WHERE data->'specs' @> '{"switches": "Cherry MX Brown"}';
 
-- GIN 索引讓整個 JSONB 都可以搜尋
CREATE INDEX idx_products_data ON products USING gin (data);
 
-- 部分更新(不用讀出-改-寫回)
UPDATE products
SET data = jsonb_set(data, '{price}', '3200')
WHERE data->>'name' = '機械鍵盤';

PG JSONB vs MongoDB 的差異:

面向PostgreSQL JSONBMongoDB
Schema可選(check constraint 可以強制)Schema-free(可用 validator)
交易完整 ACID4.0+ 多文件交易
JOIN原生 SQL JOIN$lookup(效能差)
索引GIN、Expression Index多種索引類型
生態SQL 工具鏈Mongoose、Atlas
擴展垂直為主(Citus 可水平)原生分片

判斷原則: 如果你的主力是結構化資料 + 部分 JSON 欄位,用 PG。如果你的資料九成都是非結構化文件且需要水平擴展,MongoDB 還是更自然。


「PostgreSQL 是萬能資料庫」——真相和極限

真相

PG 確實可以同時當關聯式 DB、文件 DB、搜尋引擎、向量 DB、時序 DB。對三五人的團隊來說,只維護一個 PG 比維護五個不同的資料庫合理太多了。

極限

場景PG 的極限專用方案
亞毫秒快取PG 再快也是走磁碟Redis(記憶體)
每秒百萬寫入單機寫入有天花板Cassandra / ScyllaDB
百 TB 級搜尋pg_trgm 和 tsvector 在這個量級撐不住Elasticsearch
嵌入式場景PG 需要跑 serverSQLite / DuckDB
超大規模向量pgvector HNSW 記憶體受限Pinecone / Milvus

PG 不是沒有弱點,是弱點出現的規模對大多數應用來說根本碰不到。


When NOT to use PostgreSQL

  1. 嵌入式場景:手機 App、CLI 工具、單機桌面軟體——用 SQLite
  2. 極簡場景:只需要 key-value 快取——Redis 更合適
  3. 超大規模寫入:每秒幾十萬到百萬筆——Cassandra / ScyllaDB
  4. 已有 MySQL 運行正常:不要為了潮而搬。搬資料庫的風險比效益高

從 MySQL 遷移到 PostgreSQL

如果你決定搬了,以下是實務路徑:

工具

  • pgloader:最成熟的 MySQL → PG 遷移工具,一行指令搞定
  • AWS DMS:雲端遷移服務,支援即時同步
  • pg_chameleon:Python 寫的即時複製工具

pgloader 範例

# 一行搞定
pgloader mysql://user:pass@localhost/mydb \
         postgresql://user:pass@localhost/pgdb

常見的語法差異

-- AUTO_INCREMENT → SERIAL / IDENTITY
-- MySQL
CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY);
-- PostgreSQL
CREATE TABLE users (id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY);
 
-- LIMIT offset 語法一樣
SELECT * FROM users LIMIT 10 OFFSET 20;
 
-- GROUP_CONCAT → STRING_AGG
-- MySQL
SELECT GROUP_CONCAT(name SEPARATOR ', ') FROM users;
-- PostgreSQL
SELECT STRING_AGG(name, ', ') FROM users;
 
-- IFNULL → COALESCE(COALESCE 是 SQL 標準,MySQL 也支援)
-- MySQL
SELECT IFNULL(phone, 'N/A') FROM users;
-- PostgreSQL
SELECT COALESCE(phone, 'N/A') FROM users;
 
-- 反引號 → 雙引號(或不引)
-- MySQL
SELECT `order` FROM `orders`;
-- PostgreSQL
SELECT "order" FROM orders;

遷移清單

  • 跑 pgloader 做資料遷移
  • 檢查所有隱式型別轉換的查詢
  • GROUP_CONCATSTRING_AGG
  • IFNULLCOALESCE
  • 移除反引號
  • 測試所有日期相關函式(NOW() 一樣,但 DATE_FORMATTO_CHAR
  • 確認 ORM 的 adapter 設定(Django: django.db.backends.postgresql
  • 跑完整的測試套件

常見問題

PostgreSQL 比 MySQL 慢嗎?

在純讀取的簡單查詢上,MySQL 可能稍快一點。但差距通常在毫秒級,對大多數應用沒有影響。而在複雜查詢(JOIN、子查詢、Window Functions)上,PG 的查詢優化器通常更好。

PostgreSQL 的學習曲線會不會很陡?

比 MySQL 稍微陡一點,主要是因為 PG 預設比較嚴格——型別不對就報錯、SQL 語法要更標準。但這些「嚴格」其實是在幫你。花幾天適應之後,你會感謝它。

公司已經用 MySQL 了,值得搬嗎?

通常不值得。 除非你遇到 MySQL 的具體痛點(需要 JSONB、GIS、向量搜尋等),否則搬資料庫的風險和成本通常超過收益。新專案用 PG,舊專案留 MySQL,是最務實的做法。

PostgreSQL 的擴展會不會造成版本升級困難?

會有一些。每次 PG 大版本升級(例如 15 → 16),需要確認所有擴展都支援新版。主流擴展(PostGIS, pgvector)通常在正式版發布前就準備好了,但小眾擴展可能要等。

為什麼不直接用 CockroachDB / TiDB?

因為你可能不需要分散式。NewSQL 的優勢在於水平擴展,但對 99% 的應用來說,單台 PG(加上讀取副本)就夠了。NewSQL 帶來的運維複雜度不一定值得。


本系列文章

  1. 資料庫全景圖:一張表看懂所有類型
  2. MySQL:為什麼越來越多人覺得它不夠好?
  3. PostgreSQL:為什麼它變成了預設選擇(本篇)
  4. 快取與 Session 管理:Redis、Memcached、還是直接用 DB?
  5. 全文搜尋:Elasticsearch、Meilisearch、還是 PostgreSQL 就夠了?
  6. NoSQL 什麼時候該用
  7. 資料庫設計:正規化與索引策略
  8. SQL 效能調校
  9. 資料庫遷移實戰
  10. 擴展策略:讀寫分離與分片
  11. Docker 環境的資料庫管理
  12. 資料庫監控與告警