結論先講
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+:
| 功能 | PostgreSQL | MySQL 8.0+ |
|---|---|---|
| 嚴格型別 | 天生嚴格,不允許隱式轉換 | 需設定 STRICT_TRANS_TABLES |
| JSONB | 原生二進位 JSON,GIN 索引 | JSON 型別,需 generated column 做索引 |
| Array 型別 | 原生支援 | 不支援 |
| CTE (WITH) | 8.1+(2005 年) | 8.0+(2018 年) |
| Window Functions | 8.4+(2009 年) | 8.0+(2018 年) |
| 全文搜尋 | 內建 tsvector/tsquery + 多語言 | 內建但功能較弱 |
| GIS 地理資料 | PostGIS 擴展(業界標準) | 有基本支援,遠不如 PostGIS |
| UPSERT | ON CONFLICT DO UPDATE | ON 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) | 原生 SEQUENCE | AUTO_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 JSONB | MongoDB |
|---|---|---|
| Schema | 可選(check constraint 可以強制) | Schema-free(可用 validator) |
| 交易 | 完整 ACID | 4.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 需要跑 server | SQLite / DuckDB |
| 超大規模向量 | pgvector HNSW 記憶體受限 | Pinecone / Milvus |
PG 不是沒有弱點,是弱點出現的規模對大多數應用來說根本碰不到。
When NOT to use PostgreSQL
- 嵌入式場景:手機 App、CLI 工具、單機桌面軟體——用 SQLite
- 極簡場景:只需要 key-value 快取——Redis 更合適
- 超大規模寫入:每秒幾十萬到百萬筆——Cassandra / ScyllaDB
- 已有 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_CONCAT→STRING_AGG - 改
IFNULL→COALESCE - 移除反引號
- 測試所有日期相關函式(
NOW()一樣,但DATE_FORMAT→TO_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 帶來的運維複雜度不一定值得。