别上来就比特性。先回答这些问题,答案会直接指向你的数据库:
| 维度 | PostgreSQL | MySQL | SQLite |
|---|---|---|---|
| 模型 | 客户端-服务器 | 客户端-服务器 | 嵌入式(进程内) |
| 并发模型 | MVCC(多版本并发控制) | MVCC (InnoDB) | WAL 模式(多读者 + 1 写者) |
| 存储方式 | 堆表(Heap) | 聚簇索引(主键即数据) | B-tree 文件 |
| 最大数据库 | 无硬限制 | 无硬限制 | 281TB(理论值) |
| 复制 | 流复制、逻辑复制 | Binlog、组复制 | Litestream、LiteFS |
| 连接方式 | TCP/Unix Socket | TCP/Unix Socket | 文件 I/O(零网络) |
最本质的区别:SQLite 运行在你的应用进程里。没有数据库服务器、没有 TCP 连接、没有认证。你打开一个文件,查询它。这意味着延迟可以降到微秒级——同样的主键查询,PostgreSQL 可能 2ms(含 0.5ms 网络往返),SQLite 只需 0.1ms。
| 特性 | PostgreSQL | MySQL | SQLite |
|---|---|---|---|
| 窗口函数 | ✅ 完整 | ✅ 8.0+ | ✅ 完整 |
| CTE (WITH) | ✅ 递归 | ✅ 8.0+ | ✅ 递归 |
| JSON/JSONB | ✅ 原生 JSONB + GIN 索引 | ⚠️ JSON 类型,索引有限 | ⚠️ JSON1 扩展 |
| 全文搜索 | ✅ 内置可配置 | ✅ InnoDB 全文 | ✅ FTS5 扩展 |
| 部分索引 | ✅ | ❌ | ✅ |
| 数组类型 | ✅ | ❌ | ❌ |
| 自定义类型 | ✅ enum/composite/domain | ⚠️ 仅 enum | ❌ 类型亲和 |
| UPSERT | ON CONFLICT | ON DUPLICATE KEY | ON CONFLICT |
| 扩展系统 | ✅ 极其丰富 | ⚠️ 有限 | ⚠️ 加载扩展 |
PostgreSQL 的 JSONB 是它最被低估的特性。你可以在关系型表里存 JSON 文档,用 GIN 索引查询内部字段,让它同时充当文档数据库:
-- 混合关系 + 文档模型:事件表
CREATE TABLE events (
id serial PRIMARY KEY,
data jsonb NOT NULL,
created_at timestamptz DEFAULT now()
);
-- 对 JSON 内部字段建索引
CREATE INDEX idx_events_type ON events USING GIN ((data -> 'type'));
-- 查询特定类型的事件(走索引,毫秒级)
SELECT data->>'user_id' as user_id, count(*)
FROM events
WHERE data @> '{"type": "page_view"}'
AND created_at > now() - interval '7 days'
GROUP BY data->>'user_id'
ORDER BY count(*) DESC
LIMIT 10;
这意味着:你不需要 MongoDB。PostgreSQL 的 JSONB + GIN 索引能覆盖 90% 的文档数据库场景,同时你还能享受 ACID 事务、JOIN、和外键约束。
世界上最先进的开源关系型数据库。35+ 年历史,MVCC 并发模型,扩展系统让一个数据库引擎服务多种专业场景。
| 扩展 | 用途 | SaaS 场景 |
|---|---|---|
pgvector | 向量相似性搜索 | AI 嵌入搜索、语义检索 → 向量数据库模块 |
PostGIS | 地理空间数据 | 位置服务、门店搜索 |
TimescaleDB | 时序数据 | 监控指标、IoT 数据 |
pg_cron | 定时任务 | 数据清理、报表生成 |
pg_stat_statements | 查询性能追踪 | 性能优化、慢查询定位 |
pg_audit | 审计日志 | 合规要求、数据追踪 |
Citus | 水平分片 | 大规模多租户 → 多租户模块 |
-- 方式 1:Row-Level Security (RLS) — 推荐中小规模
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON projects
USING (tenant_id = current_setting('app.current_tenant')::uuid);
-- 应用层设置当前租户
SET app.current_tenant = '550e8400-e29b-41d4-a716-446655440000';
-- 之后所有查询自动过滤,无需手动加 WHERE
SELECT * FROM projects; -- 只返回当前租户的数据
-- 方式 2:Schema 隔离 — 大规模或强隔离需求
CREATE SCHEMA tenant_acme;
CREATE SCHEMA tenant_beta;
-- 每个租户独立的表结构
CREATE TABLE tenant_acme.projects (...);
CREATE TABLE tenant_beta.projects (...);
世界上部署量最大的开源关系型数据库。InnoDB 引擎提供 ACID 事务,聚簇索引在主键查询上有天然优势。
# 创建开发分支(类似 Git 分支,生产数据可复制)
pscale branch create add-user-avatar main
# 在开发分支上修改 Schema
pscale shell mydb add-user-avatar
> ALTER TABLE users ADD COLUMN avatar_url VARCHAR(512);
# 创建部署请求(类似 PR,团队审查 Schema 变更)
pscale deploy-request create mydb add-user-avatar
# 审查通过后部署到生产
pscale deploy-request deploy mydb 1
世界上最广泛部署的数据库引擎。嵌入式、零配置、进程内运行。2024-2026 年经历「SQLite 文艺复兴」——Turso、Litestream、LiteFS 让 SQLite 从本地数据库进化为边缘就绪的分布式方案。
| 工具 | 做什么 | 原理 |
|---|---|---|
| Litestream | 持续备份到 S3 | 监控 WAL 文件,实时流式复制到对象存储。崩溃后秒级恢复。 |
| LiteFS | 多节点只读副本 | FUSE 文件系统层,主节点写入 → 副本通过 HTTP 同步。适合多区域读。 |
| Turso | 全球边缘数据库 | libSQL 分支 + 嵌入式副本 + 边缘同步。下一节详述。 |
# 安装
curl -sSfL https://litestream.io/install.sh | sh
# 配置文件 litestream.yml
dbs:
- path: /data/app.db
replicas:
- url: s3://my-bucket/app.db
retention: 24h
snapshot-interval: 1h
# 启动持续复制
litestream replicate
# 灾难恢复(从 S3 恢复到最新状态)
litestream restore -o /data/app.db s3://my-bucket/app.db
Turso 是基于 libSQL(SQLite 的开源分支)的边缘数据库服务。libSQL 保持 SQLite 文件格式和 API 兼容,同时增加了 HTTP API、嵌入式副本、边缘同步等能力。
// TypeScript: 嵌入式副本 — 本地读、远程写
import { createClient } from '@libsql/client';
const client = createClient({
url: 'file:local.db', // 本地副本
syncUrl: 'libsql://mydb.turso.io', // 远程同步源
authToken: process.env.TURSO_TOKEN,
});
// 首次启动:从远程拉取数据
await client.sync();
// 读取:从本地副本(零延迟)
const result = await client.execute('SELECT * FROM users WHERE id = ?', [userId]);
// 写入:发送到远程,异步同步回本地
await client.execute('INSERT INTO page_views (url, ts) VALUES (?, ?)', [url, Date.now()]);
await client.sync(); // 主动同步最新数据
Cloudflare 构建的 SQLite 兼容数据库,运行在 Cloudflare 的全球边缘网络上。专为 Workers 设计,无需额外基础设施。
// Cloudflare Worker + D1
export default {
async fetch(request, env) {
// env.DB 是绑定好的 D1 数据库
const { results } = await env.DB.prepare(
'SELECT * FROM users WHERE tenant_id = ? LIMIT 20'
).bind(tenantId).all();
return Response.json(results);
},
};
// wrangler.toml 配置
// [[d1_databases]]
// binding = "DB"
// database_name = "my-saas-db"
// database_id = "xxxx-xxxx"
基于 PostgreSQL 的开源 Firebase 替代品。不只提供数据库——认证、存储、实时订阅、Edge Functions 全打包。2025-2026 新增数据库分支(Git-based 预览环境)、物理读副本、后台 Edge Functions、MCP Server 集成。
| 维度 | Supabase | Firebase |
|---|---|---|
| 数据库 | PostgreSQL(关系型 + JSONB) | Firestore(NoSQL 文档型) |
| 查询能力 | ✅ 完整 SQL + JOIN + 聚合 | ⚠️ 有限查询,无 JOIN |
| 数据所有权 | ✅ 可导出 SQL、可自托管 | ❌ 锁定 Google 生态 |
| 实时 | ✅ Realtime (PostgreSQL WAL) | ✅ Realtime Updates |
| 认证 | ✅ GoTrue (OAuth/Magic Link/Phone) | ✅ Firebase Auth |
| 向量搜索 | ✅ pgvector 内置 | ❌ 需 Vertex AI |
| 定价 | 免费层够用,按量付费透明 | 免费层诱人,流量大后费用暴涨 |
| 自托管 | ✅ 完全开源可自托管 | ❌ 不可能 |
// 前端:实时监听任务变更
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
// 订阅当前租户的任务变化
supabase
.channel('tasks')
.on('postgres_changes', {
event: '*',
schema: 'public',
table: 'tasks',
filter: `tenant_id=eq.${tenantId}`,
}, (payload) => {
console.log('变更:', payload.eventType, payload.new);
updateUI(payload);
})
.subscribe();
ORM 不是必需的,但好的 ORM 能大幅提升开发效率。2026 年的 ORM 生态已经从「ORM vs 原生 SQL」的争论进化到「类型安全的查询构建器 vs 全功能 ORM」的选择。
| 维度 | Drizzle ORM | Prisma | Kysely |
|---|---|---|---|
| 类型 | 类型安全 ORM | 全功能 ORM | 类型安全查询构建器 |
| Schema 定义 | TypeScript 声明 | .prisma DSL 文件 | TypeScript 接口 |
| 迁移 | drizzle-kit generate | prisma migrate | 需第三方或手动 |
| SQL 透明度 | ✅ 生成的 SQL 可预测 | ⚠️ N+1 问题常见 | ✅ 完全控制 SQL |
| 运行时开销 | 极小(薄抽象层) | 较大(Rust 引擎 + JS 桥接) | 极小(仅查询构建) |
| 关系查询 | ✅ 关系 API + JOIN | ✅ Include/Select | ✅ 手写 JOIN |
| Edge/Serverless | ✅ 原生支持 | ⚠️ 需 Accelerate 代理 | ✅ 原生支持 |
| 学习曲线 | 中等 | 低 | 中高(需懂 SQL) |
// Schema 定义 — 纯 TypeScript,编译时类型检查
import { pgTable, uuid, varchar, timestamp, integer } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: uuid('id').defaultRandom().primaryKey(),
email: varchar('email', { length: 255 }).notNull().unique(),
name: varchar('name', { length: 100 }),
tenantId: uuid('tenant_id').notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
});
export const projects = pgTable('projects', {
id: uuid('id').defaultRandom().primaryKey(),
name: varchar('name', { length: 200 }).notNull(),
tenantId: uuid('tenant_id').notNull(),
ownerId: uuid('owner_id').references(() => users.id),
});
// 查询 — 完全类型安全,SQL 可预测
import { eq, and } from 'drizzle-orm';
const result = await db
.select()
.from(projects)
.where(and(
eq(projects.tenantId, tenantId),
eq(projects.ownerId, userId),
));
// result 的类型自动推导为 Project[] — 不需要手动定义返回类型
// schema.prisma — 声明式 DSL
model User {
id String @id @default(uuid())
email String @unique
name String?
tenantId String
projects Project[]
createdAt DateTime @default(now())
}
model Project {
id String @id @default(uuid())
name String
tenantId String
ownerId String
owner User @relation(fields: [ownerId], references: [id])
}
// 查询 — 简洁但 SQL 不透明
const projects = await prisma.project.findMany({
where: { tenantId, ownerId: userId },
include: { owner: true }, // 小心 N+1
});
// 类型定义 — 完全手动,完全控制
interface Database {
users: {
id: Generated<string>;
email: string;
name: string | null;
tenant_id: string;
};
projects: {
id: Generated<string>;
name: string;
tenant_id: string;
owner_id: string;
};
}
// 查询 — 写起来像 SQL,类型安全
const result = await db
.selectFrom('projects')
.innerJoin('users', 'users.id', 'projects.owner_id')
.select(['projects.id', 'projects.name', 'users.email as owner_email'])
.where('projects.tenant_id', '=', tenantId)
.execute();
数据库迁移是把 Schema 变更纳入版本控制的核心实践。手动改数据库 = 定时炸弹。
| 工具 | 语言 | 特点 | 适合 |
|---|---|---|---|
| drizzle-kit | TypeScript | 从 Schema 定义自动生成迁移 SQL | Drizzle ORM 用户 |
| Prisma Migrate | TypeScript | 从 .prisma 文件生成迁移,支持迁移回滚 | Prisma 用户 |
| golang-migrate | Go | 语言无关,纯 SQL 文件,支持多种数据库 | Go 项目 / 多语言团队 |
| Alembic | Python | SQLAlchemy 的迁移工具,自动生成 + 手动编辑 | Python/FastAPI 项目 |
| dbmate | Go | 极简 CLI,纯 SQL 迁移文件,支持多数据库 | 想要最简方案 |
pg_dump 再跑迁移数据库连接是昂贵的资源。PostgreSQL 每个连接 fork 一个进程,默认 100 个连接就会耗尽内存。Serverless 函数的短连接更是灾难——每个冷启动都新建连接,连接握手就要 50ms+。
| 方案 | 类型 | 原理 | 场景 |
|---|---|---|---|
| PgBouncer | 独立进程 | 事务级连接池,数千客户端共享少量数据库连接 | 生产标配,与任何框架兼容 |
| Supavisor | 独立进程 | Supabase 的连接池,多租户场景优化 | Supabase 用户 |
| Neon Serverless Driver | HTTP | 通过 HTTP/WebSocket 连接,无需 TCP | Edge/Serverless 环境 |
| Prisma Accelerate | 托管服务 | Prisma 专属的边缘连接池 | Prisma + Edge |
# pgbouncer.ini
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb
[pgbouncer]
# 事务模式:事务结束就释放连接(最节省连接数)
pool_mode = transaction
# 连接池大小:每个数据库/用户对的最大连接数
max_client_conn = 1000
default_pool_size = 25
# 空闲连接超时
server_idle_timeout = 300
# 监听端口
listen_port = 6432
listen_addr = 0.0.0.0
SET 语句和临时表会在事务结束时丢失。如果需要跨事务保持状态,使用会话级连接池(但连接数会更多)。PostgreSQL 14+ 的 ALTER SYSTEM SET 和 pg_catalog 操作需要直连,不能走连接池。
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 🆕 新 SaaS 项目 (0→1) | PostgreSQL + Drizzle | 默认选择,功能最全,类型安全 |
| 🚀 快速 MVP / 原型 | Supabase + Prisma | 全栈后端开箱即用,最低学习成本 |
| 📱 单服务器应用 | SQLite + Litestream | 零运维、超低延迟、自动备份 |
| 🌍 全球边缘部署 | Turso + Drizzle | 嵌入式副本 + 边缘同步 + 类型安全 |
| ☁️ Cloudflare Workers | D1 + Drizzle | 原生集成,零配置 |
| 🤖 AI/Agent 应用 | PostgreSQL + pgvector | OLTP + 向量搜索一体化 → 向量数据库 |
| 📊 分析密集型 | PostgreSQL + TimescaleDB | 时序数据 + OLTP 不二选 |
| 🏢 大规模多租户 | PostgreSQL + Citus | 水平分片,透明分布式 → 多租户架构 |
| 🔄 已有 MySQL 基础设施 | MySQL + PlanetScale | 不迁移 + 获得分支工作流 |
| 🐍 Python/FastAPI 栈 | PostgreSQL + SQLAlchemy + Alembic | Python 生态最成熟的组合 |
大多数 SaaS 只需要一个 PostgreSQL。但以下场景可能需要补充:
| 补充需求 | 补充方案 | 与主库的分工 |
|---|---|---|
| 全文搜索 | Meilisearch / Typesense | PG 的 FTS 够用则不需要;复杂搜索场景用专用引擎 |
| 向量搜索 | LanceDB / ChromaDB | PG + pgvector 够用则不需要;百万级向量以上考虑专用 → 向量数据库 |
| 缓存 | Redis / Upstash | 会话、速率限制、热数据缓存 → 缓存策略 |
| 队列 | Redis / SQS / Inngest | 异步任务处理 → 异步任务 |
| 时序数据 | TimescaleDB | PG 扩展,不需要额外数据库 |