不同数据库系统的兼容性对比

October, 10th 2025 4 min read

更新时间:2025-09-07

本文档总结了在使用 Cloudflare D1 进行前期开发时,如何兼顾 MySQLPostgreSQL 的兼容性设计,确保后续迁移成本可控。


1. 总体思路

  • Serverless 无状态 → 所有业务状态需外部化存储。
  • D1(SQLite 托管):MVP/内部工具首选,无需运维。
  • 迁移原则
    1. Schema 设计时采用 跨库最小公约数
    2. 数据访问层(Repository / DAL)收口;
    3. 使用 Drizzle ORM 等跨方言 Query Builder;
    4. 数据迁移通过导出 → 导入 → 校验 → 切换完成。

2. 数据类型对比

概念D1 (SQLite)MySQLPostgreSQL建议写法
主键INTEGER PRIMARY KEY (rowid) / TEXTAUTO_INCREMENT / UUIDSERIAL/BIGSERIAL / UUIDUUID/ULID (TEXT/CHAR)
整数INTEGER (64bit 动态)TINYINT/INT/BIGINTSMALLINT/INTEGER/BIGINTINTEGER/BIGINT
小数REALFLOAT/DOUBLE/DECIMALREAL/DOUBLE/NUMERICNUMERIC(p,s)
字符串TEXTVARCHAR(n)/TEXTVARCHAR(n)/TEXTTEXTVARCHAR(191)
布尔无,常用 0/1BOOLEAN (实际 tinyint)BOOLEANINTEGER 0/1
日期时间TEXT/INTEGER (epoch)DATETIME/TIMESTAMPTIMESTAMP [TZ]BIGINT 毫秒时间戳
JSONTEXT + json1 扩展JSONJSONBTEXT (应用层 parse)
二进制BLOBBLOB/VARBINARYBYTEABLOB/BYTEA

3. SQL 功能差异

功能D1 (SQLite)MySQLPostgreSQL建议
自动增长INTEGER PRIMARY KEY rowidAUTO_INCREMENTSERIAL/BIGSERIAL避免,用 UUID
UPSERTON CONFLICT(col) DO UPDATEON DUPLICATE KEY UPDATEON CONFLICT(col) DO UPDATE用 ORM API
字符串拼接``CONCAT()``ORM 封装
JSON 提取json_extract(text,'$.k')JSON_EXTRACT()->, ->>, #>>应用层解析
外键支持,需 PRAGMA foreign_keys=ON支持支持显式定义
窗口函数3.25+ 支持8.0+ 支持原生支持注意版本

4. Schema 设计规范

  1. 主键:统一 UUID/ULID (TEXT/CHAR(26)),避免自增。
  2. 时间戳:统一 BIGINT 毫秒数。
  3. 布尔:统一 INTEGER 0/1
  4. JSON:统一 TEXT 存储,应用层 parse。
  5. 索引/唯一约束:显式声明,避免隐式行为。
  6. 避免 SQLite 专属语法(如 WITHOUT ROWID)。

5. DDL 示例

5.1 D1 / SQLite

sql
1234567
      CREATE TABLE users (
  id TEXT PRIMARY KEY,
  username TEXT NOT NULL UNIQUE,
  password_hash TEXT NOT NULL,
  is_admin INTEGER NOT NULL DEFAULT 0,
  created_at INTEGER NOT NULL
);
    

5.2 MySQL

sql
1234567
      CREATE TABLE users (
  id CHAR(26) PRIMARY KEY,
  username VARCHAR(191) NOT NULL UNIQUE,
  password_hash TEXT NOT NULL,
  is_admin TINYINT NOT NULL DEFAULT 0,
  created_at BIGINT NOT NULL
) ENGINE=InnoDB;
    

5.3 PostgreSQL

sql
1234567
      CREATE TABLE users (
  id TEXT PRIMARY KEY,
  username TEXT NOT NULL UNIQUE,
  password_hash TEXT NOT NULL,
  is_admin INTEGER NOT NULL DEFAULT 0,
  created_at BIGINT NOT NULL
);
    

其余表(sessions、questions、submissions 等)同理,字段规则保持一致。


6. 迁移注意事项

  • UPSERT 语法:SQLite/PG 相同,MySQL 不同 → ORM 封装。
  • 布尔/时间戳/JSON:建议统一为 0/1、BIGINT、TEXT,迁移最顺滑。
  • 外键:SQLite 默认关闭,记得 PRAGMA foreign_keys=ON
  • 数据迁移流程
    1. wrangler d1 export → CSV/NDJSON;
    2. 导入目标库(MySQL/PG);
    3. 校验行数 & 唯一约束;
    4. 测试通过后切换 DAL 数据源。

7. 代码层面最佳实践

  • Repository 模式:定义接口,应用层不直接写 SQL。
  • Drizzle ORM:支持 D1/PG/MySQL 驱动,Schema 一份,驱动可切换。
  • 示例
ts
1234
      export interface UserRepo {
  create(u:{id:string; username:string; pass:string; at:number}):Promise<void>;
  findByUsername(name:string):Promise<User|null>;
}
    

不同实现:

  • user.repo.d1.ts → 用 drizzle/d1。
  • user.repo.pg.ts → 用 drizzle/pg。
  • user.repo.mysql.ts → 用 drizzle/mysql。

切换时只换绑定,不动业务代码。


8. 总结

  • D1:轻量、无运维,适合 MVP。
  • MySQL:高并发、事务型业务。
  • PostgreSQL:功能全,适合复杂查询与扩展。
  • 迁移核心:提前规划 Schema(UUID/时间戳/布尔/JSON),用 ORM 屏蔽方言差异。
  • 最终收益:后续切库时,应用逻辑几乎不用改,主要工作是数据迁移。