🗄️ 数据库选型

PostgreSQL / MySQL / SQLite / D1 / Turso / Supabase — 选型的本质不是「哪个更好」,而是「我的场景需要什么」。加上 ORM、迁移、连接池,构成完整的数据库决策框架。

01 数据库选型决策树

别上来就比特性。先回答这些问题,答案会直接指向你的数据库:

❓ 你的应用需要多台服务器同时写入吗?
不需要(单服务器) → SQLite / Turso 是第一选择
需要 → 继续往下
❓ 你的数据模型是关系型还是文档型?
关系型(多表 JOIN、事务) → PostgreSQL
文档型(灵活 schema、嵌套结构) → PostgreSQL JSONB 或 MongoDB
❓ 你需要向量搜索(AI/ML)吗?
需要 → PostgreSQL + pgvector(一个库搞定 OLTP + 向量)
❓ 你需要全球低延迟(多区域部署)?
需要 → Turso(嵌入式副本 + 边缘同步)
❓ 你在 Cloudflare Workers 上构建?
是 → D1(唯一原生选择)
❓ 你想最快上线,不想管基础设施?
想 → Supabase / PlanetScale / Neon(托管 PostgreSQL)
核心原则:如果你没有明确的理由选别的,选 PostgreSQL。它是 2026 年新项目的默认选择——不是因为它是「最好的」,而是因为它的生态、社区、扩展性让大多数场景都有成熟解法。

02 三大主流数据库深度对比

架构本质差异

维度PostgreSQLMySQLSQLite
模型客户端-服务器客户端-服务器嵌入式(进程内)
并发模型MVCC(多版本并发控制)MVCC (InnoDB)WAL 模式(多读者 + 1 写者)
存储方式堆表(Heap)聚簇索引(主键即数据)B-tree 文件
最大数据库无硬限制无硬限制281TB(理论值)
复制流复制、逻辑复制Binlog、组复制Litestream、LiteFS
连接方式TCP/Unix SocketTCP/Unix Socket文件 I/O(零网络)

最本质的区别:SQLite 运行在你的应用进程里。没有数据库服务器、没有 TCP 连接、没有认证。你打开一个文件,查询它。这意味着延迟可以降到微秒级——同样的主键查询,PostgreSQL 可能 2ms(含 0.5ms 网络往返),SQLite 只需 0.1ms。

SQL 特性对比

特性PostgreSQLMySQLSQLite
窗口函数✅ 完整✅ 8.0+✅ 完整
CTE (WITH)✅ 递归✅ 8.0+✅ 递归
JSON/JSONB✅ 原生 JSONB + GIN 索引⚠️ JSON 类型,索引有限⚠️ JSON1 扩展
全文搜索✅ 内置可配置✅ InnoDB 全文✅ FTS5 扩展
部分索引
数组类型
自定义类型✅ enum/composite/domain⚠️ 仅 enum❌ 类型亲和
UPSERTON CONFLICTON DUPLICATE KEYON CONFLICT
扩展系统✅ 极其丰富⚠️ 有限⚠️ 加载扩展

PostgreSQL 的 JSONB:一个数据库搞定两件事

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、和外键约束。

03 PostgreSQL:2026 年的默认选择

是什么

世界上最先进的开源关系型数据库。35+ 年历史,MVCC 并发模型,扩展系统让一个数据库引擎服务多种专业场景。

何时用

何时不用

关键扩展

扩展用途SaaS 场景
pgvector向量相似性搜索AI 嵌入搜索、语义检索 → 向量数据库模块
PostGIS地理空间数据位置服务、门店搜索
TimescaleDB时序数据监控指标、IoT 数据
pg_cron定时任务数据清理、报表生成
pg_stat_statements查询性能追踪性能优化、慢查询定位
pg_audit审计日志合规要求、数据追踪
Citus水平分片大规模多租户 → 多租户模块

代码示例:SaaS 多租户基础设置

-- 方式 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 (...);
Agent 架构关联:Agent 研究报告 中,OpenClaw 使用 PostgreSQL 存储会话和轨迹数据,Hermes 使用 PostgreSQL + pgvector 做语义记忆检索。pgvector 让 Agent 的「记忆」不必依赖独立的向量数据库——一个 PostgreSQL 实例同时处理 OLTP 和向量搜索。

04 MySQL:老牌但正在失去新项目

是什么

世界上部署量最大的开源关系型数据库。InnoDB 引擎提供 ACID 事务,聚簇索引在主键查询上有天然优势。

何时用

何时不用

优劣对比

✅ 优势
  • 聚簇索引:主键查询极快,数据物理排序
  • 部署量最大:运维经验丰富,人才多
  • PlanetScale:数据库分支,Schema 变更像代码审查
  • 社区成熟:问题几乎都能搜到解法
❌ 劣势
  • Gap Locking:高并发写入容易出现锁争用
  • JSON 支持弱:有类型但索引和查询能力远不如 PG JSONB
  • 扩展生态差:没有 pgvector/PostGIS 级别的扩展
  • 部分索引缺失:无法只索引满足条件的行
  • 新功能总是慢半拍:窗口函数/CTE 到 8.0 才有

代码示例:PlanetScale 分支工作流

# 创建开发分支(类似 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

05 SQLite:被低估的生产级选择

是什么

世界上最广泛部署的数据库引擎。嵌入式、零配置、进程内运行。2024-2026 年经历「SQLite 文艺复兴」——Turso、Litestream、LiteFS 让 SQLite 从本地数据库进化为边缘就绪的分布式方案。

何时用

何时不用

SQLite 文艺复兴:三个关键工具

工具做什么原理
Litestream持续备份到 S3监控 WAL 文件,实时流式复制到对象存储。崩溃后秒级恢复。
LiteFS多节点只读副本FUSE 文件系统层,主节点写入 → 副本通过 HTTP 同步。适合多区域读。
Turso全球边缘数据库libSQL 分支 + 嵌入式副本 + 边缘同步。下一节详述。

代码示例:Litestream 持续备份

# 安装
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
SQLite 最大的误解:「SQLite 不适合生产环境」。37signals(Ruby on Rails 创造者)已经在生产中运行多个 SQLite 应用。关键不是 SQLite 能不能上生产,而是你的场景是否适合——大多数早期 SaaS 完全适合。

06 Turso / libSQL:SQLite 的边缘进化

是什么

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(); // 主动同步最新数据
与 Agent 架构的关系:如果你在构建一个边缘部署的 Agent 系统(如 OpenClaw 的多区域部署),Turso 的嵌入式副本模式让 Agent 可以在本地低延迟读取会话历史,同时保持全局一致性。

07 Cloudflare D1:Workers 的原生数据库

是什么

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"

08 Supabase:PostgreSQL 的全托管体验

是什么

基于 PostgreSQL 的开源 Firebase 替代品。不只提供数据库——认证、存储、实时订阅、Edge Functions 全打包。2025-2026 新增数据库分支(Git-based 预览环境)、物理读副本、后台 Edge Functions、MCP Server 集成。

Supabase vs Firebase

维度SupabaseFirebase
数据库PostgreSQL(关系型 + JSONB)Firestore(NoSQL 文档型)
查询能力✅ 完整 SQL + JOIN + 聚合⚠️ 有限查询,无 JOIN
数据所有权✅ 可导出 SQL、可自托管❌ 锁定 Google 生态
实时✅ Realtime (PostgreSQL WAL)✅ Realtime Updates
认证✅ GoTrue (OAuth/Magic Link/Phone)✅ Firebase Auth
向量搜索✅ pgvector 内置❌ 需 Vertex AI
定价免费层够用,按量付费透明免费层诱人,流量大后费用暴涨
自托管✅ 完全开源可自托管❌ 不可能

代码示例:Supabase 实时订阅

// 前端:实时监听任务变更
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();
Agent 关联:Supabase 是 GPT Researcher 使用的向量存储后端(pgvector),也是 OpenClaw 可选的存储方案。它的 MCP Server 集成让 AI Agent 可以直接操作数据库——这是 Agent-native 应用的基础设施选择。

09 ORM 选型:类型安全 vs 灵活控制

ORM 不是必需的,但好的 ORM 能大幅提升开发效率。2026 年的 ORM 生态已经从「ORM vs 原生 SQL」的争论进化到「类型安全的查询构建器 vs 全功能 ORM」的选择。

三大 ORM 对比

维度Drizzle ORMPrismaKysely
类型类型安全 ORM全功能 ORM类型安全查询构建器
Schema 定义TypeScript 声明.prisma DSL 文件TypeScript 接口
迁移drizzle-kit generateprisma migrate需第三方或手动
SQL 透明度✅ 生成的 SQL 可预测⚠️ N+1 问题常见✅ 完全控制 SQL
运行时开销极小(薄抽象层)较大(Rust 引擎 + JS 桥接)极小(仅查询构建)
关系查询✅ 关系 API + JOIN✅ Include/Select✅ 手写 JOIN
Edge/Serverless✅ 原生支持⚠️ 需 Accelerate 代理✅ 原生支持
学习曲线中等中高(需懂 SQL)

Drizzle ORM:2026 年的新宠

// 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[] — 不需要手动定义返回类型

Prisma:快速启动的选择

// 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
});

Kysely:SQL 高手的选择

// 类型定义 — 完全手动,完全控制
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();
选择建议:新项目用 Drizzle——类型安全 + SQL 透明 + Edge 友好,三者兼得。如果你团队 SQL 水平高且想要完全控制,Kysely 更爽。如果你想要最低学习曲线、最快出活,Prisma 够用但要注意 N+1。

10 数据库迁移:Schema 变更的安全网

数据库迁移是把 Schema 变更纳入版本控制的核心实践。手动改数据库 = 定时炸弹。

迁移工具对比

工具语言特点适合
drizzle-kitTypeScript从 Schema 定义自动生成迁移 SQLDrizzle ORM 用户
Prisma MigrateTypeScript从 .prisma 文件生成迁移,支持迁移回滚Prisma 用户
golang-migrateGo语言无关,纯 SQL 文件,支持多种数据库Go 项目 / 多语言团队
AlembicPythonSQLAlchemy 的迁移工具,自动生成 + 手动编辑Python/FastAPI 项目
dbmateGo极简 CLI,纯 SQL 迁移文件,支持多数据库想要最简方案

迁移最佳实践

  1. 每个迁移只做一件事:一个迁移只加一列或只建一表,不要混合
  2. 永远不要修改已部署的迁移:改了就新建一个 ALTER 迁移
  3. 可逆迁移:每个 UP 都要有对应的 DOWN
  4. 零停机迁移:加列(有默认值)✅ → 改列类型 ❌ → 需要多步迁移
    • 步骤 1:加新列(并行写入新旧列)
    • 步骤 2:迁移旧数据
    • 步骤 3:代码切到新列
    • 步骤 4:删旧列
  5. 迁移要纳入 CI:在 CI 中运行迁移确保不会失败
  6. 生产前备份:永远先 pg_dump 再跑迁移

11 连接池:生产环境的必选项

数据库连接是昂贵的资源。PostgreSQL 每个连接 fork 一个进程,默认 100 个连接就会耗尽内存。Serverless 函数的短连接更是灾难——每个冷启动都新建连接,连接握手就要 50ms+。

连接池方案

方案类型原理场景
PgBouncer独立进程事务级连接池,数千客户端共享少量数据库连接生产标配,与任何框架兼容
Supavisor独立进程Supabase 的连接池,多租户场景优化Supabase 用户
Neon Serverless DriverHTTP通过 HTTP/WebSocket 连接,无需 TCPEdge/Serverless 环境
Prisma Accelerate托管服务Prisma 专属的边缘连接池Prisma + Edge

代码示例:PgBouncer 配置

# 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 SETpg_catalog 操作需要直连,不能走连接池。

12 场景推荐速查表

场景推荐方案理由
🆕 新 SaaS 项目 (0→1)PostgreSQL + Drizzle默认选择,功能最全,类型安全
🚀 快速 MVP / 原型Supabase + Prisma全栈后端开箱即用,最低学习成本
📱 单服务器应用SQLite + Litestream零运维、超低延迟、自动备份
🌍 全球边缘部署Turso + Drizzle嵌入式副本 + 边缘同步 + 类型安全
☁️ Cloudflare WorkersD1 + Drizzle原生集成,零配置
🤖 AI/Agent 应用PostgreSQL + pgvectorOLTP + 向量搜索一体化 → 向量数据库
📊 分析密集型PostgreSQL + TimescaleDB时序数据 + OLTP 不二选
🏢 大规模多租户PostgreSQL + Citus水平分片,透明分布式 → 多租户架构
🔄 已有 MySQL 基础设施MySQL + PlanetScale不迁移 + 获得分支工作流
🐍 Python/FastAPI 栈PostgreSQL + SQLAlchemy + AlembicPython 生态最成熟的组合

13 替代方案与补充

什么时候需要不止一个数据库?

大多数 SaaS 只需要一个 PostgreSQL。但以下场景可能需要补充:

补充需求补充方案与主库的分工
全文搜索Meilisearch / TypesensePG 的 FTS 够用则不需要;复杂搜索场景用专用引擎
向量搜索LanceDB / ChromaDBPG + pgvector 够用则不需要;百万级向量以上考虑专用 → 向量数据库
缓存Redis / Upstash会话、速率限制、热数据缓存 → 缓存策略
队列Redis / SQS / Inngest异步任务处理 → 异步任务
时序数据TimescaleDBPG 扩展,不需要额外数据库
反模式警告:不要因为「未来可能需要」就引入第二个数据库。每个额外的数据库都是运维成本、数据一致性挑战、和团队认知负担。先用 PostgreSQL 一个库做到极致,等性能或功能真正遇到瓶颈再加。

14 关键链接