关系型数据库选型

要点

  • PostgreSQL、MySQL、SQLite 是 Hono 项目最常用的三种关系型数据库
  • PostgreSQL 功能最全面,JSON 支持好,扩展丰富,是 AI 项目的首选
  • MySQL 生态成熟,云服务商支持好,团队熟悉度高
  • SQLite 轻量零配置,适合开发、测试和小项目,Cloudflare D1 基于 SQLite
  • Edge 环境(Workers、Deno Deploy)通常只能用远程连接或 SQLite
  • 选型时团队熟悉度往往比技术差异更重要

1. 三大数据库概览

维度PostgreSQLMySQLSQLite
定位功能全面的企业级数据库生态成熟的 Web 数据库嵌入式轻量数据库
JSON 支持JSONB,索引和查询能力强JSON 类型,功能较弱JSON1 扩展,基础支持
向量支持pgvector 扩展无原生支持sqlite-vss 扩展
并发模型多版本并发控制(MVCC)锁机制单写者
事务完整 ACID,支持多种隔离级别完整 ACID完整 ACID
扩展性扩展丰富(PostGIS、pgvector 等)插件较少扩展有限
部署需要独立服务需要独立服务嵌入式,无服务
云托管各大云均有各大云均有无(除 D1)

2. PostgreSQL

PostgreSQL 是 AI 项目的首选关系型数据库,原因:

  1. JSONB 类型:可以在关系型表里存储 JSON,支持 GIN 索引,查询性能接近专用文档数据库
  2. pgvector 扩展:同一数据库存储业务数据和向量数据,减少运维复杂度
  3. 扩展生态:PostGIS(地理信息)、TimescaleDB(时序数据)等扩展覆盖各种场景
  4. 标准兼容:严格遵循 SQL 标准,迁移到其他数据库时语法差异小

2.1 与 Hono 集成

// src/lib/db.ts
import { Pool } from 'pg'
import { drizzle } from 'drizzle-orm/node-postgres'
import * as schema from './schema'
 
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
})
 
export const db = drizzle(pool, { schema })
// src/schema.ts
import { pgTable, uuid, text, timestamp, jsonb } from 'drizzle-orm/pg-core'
 
export const users = pgTable('users', {
  id: uuid('id').primaryKey().defaultRandom(),
  email: text('email').notNull().unique(),
  name: text('name').notNull(),
  metadata: jsonb('metadata'),  // JSONB 类型
  createdAt: timestamp('created_at').defaultNow(),
})

2.2 pgvector 集成

// src/schema.ts
import { pgTable, uuid, text, vector } from 'drizzle-orm/pg-core'
 
export const documentEmbeddings = pgTable('document_embeddings', {
  id: uuid('id').primaryKey().defaultRandom(),
  documentId: uuid('document_id').notNull(),
  chunk: text('chunk').notNull(),
  embedding: vector('embedding', { dimensions: 1536 }).notNull(),
  createdAt: timestamp('created_at').defaultNow(),
})
// 相似度查询
import { sql } from 'drizzle-orm'
import { db } from './lib/db'
import { documentEmbeddings } from './schema'
 
const queryEmbedding = [0.1, 0.2, ...]  // 1536 维
 
const results = await db
  .select({
    id: documentEmbeddings.id,
    chunk: documentEmbeddings.chunk,
    similarity: sql`1 - (${documentEmbeddings.embedding} <=> ${queryEmbedding})`,
  })
  .from(documentEmbeddings)
  .orderBy(sql`${documentEmbeddings.embedding} <=> ${queryEmbedding}`)
  .limit(5)

2.3 适用场景

  • 需要 JSONB 存储半结构化数据
  • 需要向量检索(pgvector)
  • 需要地理信息(PostGIS)
  • 团队有一定 PostgreSQL 经验
  • 项目可能扩展到复杂查询场景

3. MySQL

MySQL 是国内使用最广泛的关系型数据库,优势:

  1. 生态成熟:云服务商、ORM、工具链支持完善
  2. 团队熟悉:国内开发者普遍熟悉 MySQL
  3. 云托管丰富:阿里云 RDS、腾讯云 CDB、AWS RDS 等
  4. 性能稳定:读性能优秀,适合读多写少的场景

3.1 与 Hono 集成

// src/lib/db.ts
import { createPool } from 'mysql2/promise'
import { drizzle } from 'drizzle-orm/mysql2'
import * as schema from './schema'
 
const pool = await createPool({
  uri: process.env.DATABASE_URL,
})
 
export const db = drizzle(pool, { schema })
// src/schema.ts
import { mysqlTable, varchar, json, timestamp } from 'drizzle-orm/mysql-core'
 
export const users = mysqlTable('users', {
  id: varchar('id', { length: 36 }).primaryKey(),
  email: varchar('email', { length: 255 }).notNull().unique(),
  name: varchar('name', { length: 255 }).notNull(),
  metadata: json('metadata'),  // JSON 类型
  createdAt: timestamp('created_at').defaultNow(),
})

3.2 与 PostgreSQL 的差异

  1. JSON 支持:MySQL 的 JSON 类型功能较弱,不支持索引(5.7+ 支持生成列索引)
  2. 向量支持:无原生向量扩展,需要外部向量数据库
  3. 语法差异:自增主键、字符串函数、日期函数等有差异
  4. 事务隔离:默认隔离级别不同(MySQL 默认 REPEATABLE READ,PostgreSQL 默认 READ COMMITTED)

3.3 适用场景

  • 团队熟悉 MySQL
  • 云服务商提供优质的 MySQL 托管服务
  • 不需要复杂的 JSON 查询或向量检索
  • 读多写少的场景

4. SQLite

SQLite 是嵌入式数据库,数据存在单个文件里,不需要独立的服务进程。

优势:

  1. 零配置:不需要安装、启动数据库服务
  2. 轻量:单个文件,便于备份和迁移
  3. 性能:读性能优秀,适合读多写少
  4. Edge 兼容:Cloudflare D1 基于 SQLite,适合 Workers 环境

限制:

  1. 单写者:同一时刻只能有一个写操作,不适合高并发写入
  2. 无网络访问:本地文件,不能跨机器共享
  3. 扩展有限:功能不如 PostgreSQL 和 MySQL 丰富

4.1 本地开发

SQLite 是本地开发的最佳选择——不需要启动数据库服务,数据存在文件里,重启不丢失:

// src/lib/db.ts
import Database from 'better-sqlite3'
import { drizzle } from 'drizzle-orm/better-sqlite3'
import * as schema from './schema'
 
const sqlite = new Database('local.db')
export const db = drizzle(sqlite, { schema })

4.2 Cloudflare D1

D1 是 Cloudflare Workers 的托管 SQLite 服务:

// src/lib/db.ts
import { drizzle } from 'drizzle-orm/d1'
import * as schema from './schema'
 
export interface Env {
  DB: D1Database
}
 
export default {
  async fetch(request: Request, env: Env) {
    const db = drizzle(env.DB, { schema })
    // 使用 db 查询
  },
}

D1 的限制:

  • 数据库大小限制 10GB(免费)或 100GB(付费)
  • 每天写入次数有限(免费 5M 行,付费 50M 行)
  • 不支持某些 SQLite 扩展

4.3 适用场景

  • 本地开发和测试
  • 小项目、原型验证
  • Cloudflare Workers 环境
  • 读多写少的场景
  • 数据量小(单表少于百万行)

5. 选型决策树

是否需要 Edge 环境(Workers、Deno Deploy)?
├── 是 → 数据量小?
│        ├── 是 → SQLite / D1
│        └── 否 → 远程连接 PostgreSQL / MySQL
└── 否 → 是否需要 JSON 查询或向量检索?
         ├── 是 → PostgreSQL(pgvector)
         └── 否 → 团队熟悉度?
                  ├── PostgreSQL → PostgreSQL
                  ├── MySQL → MySQL
                  └── 都不熟悉 → PostgreSQL(功能更全面)

6. 环境差异化配置

实际项目里,不同环境可能使用不同的数据库:

// src/lib/db.ts
import { Pool } from 'pg'
import Database from 'better-sqlite3'
import { drizzle } from 'drizzle-orm/node-postgres'
import { drizzle as drizzleSqlite } from 'drizzle-orm/better-sqlite3'
 
const env = process.env.NODE_ENV
 
if (env === 'production' || env === 'staging') {
  // 生产环境用 PostgreSQL
  const pool = new Pool({ connectionString: process.env.DATABASE_URL })
  export const db = drizzle(pool, { schema })
} else {
  // 开发/测试环境用 SQLite
  const sqlite = new Database('local.db')
  export const db = drizzleSqlite(sqlite, { schema })
}

Drizzle 支持多种数据库后端,schema 定义可以复用:

// src/schema.ts
// 这个 schema 可以同时用于 PostgreSQL 和 SQLite
import { pgTable, uuid, text } from 'drizzle-orm/pg-core'
// 或
import { sqliteTable, text } from 'drizzle-orm/sqlite-core'
 
// 但通常建议按数据库类型分开定义

7. 迁移考量

如果项目后期需要迁移数据库(例如从 SQLite 迁移到 PostgreSQL),需要注意:

  1. 数据类型差异:SQLite 的 TEXT vs PostgreSQL 的 VARCHAR、UUID 等
  2. 自增主键:SQLite 的 INTEGER PRIMARY KEY vs PostgreSQL 的 SERIALUUID
  3. 日期时间:SQLite 存字符串,PostgreSQL 有 TIMESTAMP 类型
  4. JSON:SQLite 的 JSON1 vs PostgreSQL 的 JSONB
  5. 迁移工具:Drizzle Kit 支持生成不同数据库的迁移脚本

迁移成本在可控范围内,前提是使用 ORM 而不是手写 SQL。

8. 性能基准

简单的性能对比(仅供参考,实际性能取决于具体场景):

操作PostgreSQLMySQLSQLite
单行插入
批量插入
主键查询
范围查询
复杂 JOIN中等
并发写入好(MVCC)中等差(单写者)
JSON 查询快(JSONB)
向量检索快(pgvector)不支持慢(sqlite-vss)

SQLite 在并发写入场景下性能差,是因为同一时刻只能有一个写事务。如果项目有高并发写入需求,不要用 SQLite。

总结

关系型数据库选型是 AI 项目的基础决策。PostgreSQL、MySQL、SQLite 各有适用场景。

这一节涉及到的几个判断:

  1. PostgreSQL:功能最全面,JSON 支持好,pgvector 支持向量检索,是 AI 项目的首选
  2. MySQL:生态成熟,团队熟悉度高,适合不需要复杂 JSON 查询或向量检索的项目
  3. SQLite:零配置、轻量,适合开发测试、小项目、Edge 环境
  4. Edge 环境:Cloudflare Workers 用 D1(SQLite),其他 Edge 环境远程连接
  5. 环境差异化:生产用 PostgreSQL/MySQL,开发用 SQLite
  6. 迁移成本:使用 ORM 可以降低迁移成本

选型原则:

  • 先考虑环境约束:Edge 环境只能用 SQLite 或远程连接
  • 再考虑功能需求:需要 JSON 查询或向量检索,选 PostgreSQL
  • 最后考虑团队熟悉度:功能差异不大时,团队熟悉哪个用哪个

下一篇看 PostgreSQL 实践——深入 PostgreSQL 的特性,以及与 Hono 项目的集成细节。