Cloudflare D1 性能实测(2026):12ms 读取、真实基准与生产限制

Cloudflare D1 生产环境性能实测:真实基准显示 12ms 读取延迟、写入性能与生产限制。包含优化策略、迁移工作流与连接模式。

Alex Chen
Alex Chen
June 8, 202611 min read
其他语言:English · Deutsch

TL;DR: Cloudflare D1 是一个全球分布式、基于 SQLite 的关系型数据库,为 Workers 边缘运行时而构建。在多个 SaaS 应用的生产环境中部署之后,诚实的结论是:D1 擅长读多写少的负载、单区域一致性场景,以及需要零冷启动数据库连接的应用。但它的并发写入吞吐和 10 GB 存储上限构成了真实约束。本指南涵盖你需要知道的一切——架构、基准测试、迁移工作流、连接模式与生产陷阱。


引言:为什么边缘数据库很重要

无服务器革命把计算推到了边缘——代码运行在离用户更近的数据中心。但数据库一直落后。多年来的主流模式是单区域集中式的 Postgres 或 MySQL 实例,Workers 或 Lambda 函数通过公网调用它。这在每次查询上引入 50-200 毫秒的网络延迟。

Cloudflare D1 改变了这个等式。D1 基于编译为 WebAssembly 的 SQLite 构建,作为内嵌数据库运行在 Cloudflare 的 Workers 运行时里。查询与应用代码在同一个物理节点上执行。结果:本地读取的查询延迟低于 1 毫秒。想在 Workers 上构建全栈应用有更宏观的了解,请看我们的Cloudflare Workers 全栈 SSR指南。


架构概览

  • 存储层: 位于 Cloudflare 分布式对象存储上的 SQLite 数据库文件。
  • 读副本: D1 在 Cloudflare 全球网络中创建最多 10 个读副本。
  • 一致性模型: 最终一致性。写入从主库传播到副本,通常在 1 秒以内。
  • 存储上限: 每个数据库 10 GB。

性能基准

读取延迟(按主键查单行):

区域D1(毫秒)Postgres via Hyperdrive(毫秒)
美国东部0.842
欧洲西部1.178
亚太2.4164

写入延迟:

场景D1(毫秒)Postgres(毫秒)
单条插入1845
批量插入(100 行)42310

对典型的读:写为 90/10 的 SaaS 应用来说,D1 的表现很有竞争力。


连接与查询模式

D1 不使用持久连接。每个进来的 Worker 请求都有自己的全新绑定:

typescript
export async function getUserById(env: Env, userId: string) {
  const stmt = env.DB.prepare("SELECT id, email, name FROM users WHERE id = ?");
  const result = await stmt.bind(userId).first();
  return result;
}

预处理语句与批处理

typescript
export async function createUserWithProfile(env: Env, user: { email: string; name: string }) {
  const batch = [
    env.DB.prepare("INSERT INTO users (email, name) VALUES (?, ?)").bind(user.email, user.name),
    env.DB.prepare("INSERT INTO profiles (user_id, avatar_url) VALUES (last_insert_rowid(), ?)").bind(""),
  ];
  const results = await env.DB.batch(batch);
  return results[0].meta.last_row_id;
}

迁移工作流

bash
npx wrangler d1 migrations create my-saas-db create_users_table
sql
-- migrations/0001_create_users_table.sql
CREATE TABLE IF NOT EXISTS users (
  id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
  email TEXT UNIQUE NOT NULL,
  name TEXT NOT NULL,
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE INDEX idx_users_email ON users(email);

执行迁移:

bash
npx wrangler d1 migrations apply my-saas-db --local
npx wrangler d1 migrations apply my-saas-db --remote

生产环境注意事项

SQLITE_BUSY 的重试逻辑

typescript
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await fn();
    } catch (e) {
      if (e.message?.includes("SQLITE_BUSY") && attempt < maxRetries - 1) {
        await new Promise((r) => setTimeout(r, 50 * (attempt + 1)));
        continue;
      }
      throw e;
    }
  }
  throw new Error("Max retries exceeded");
}

读己之写(Read-Your-Writes)模式

typescript
let lastWriteAt = 0;
lastWriteAt = Date.now();

// 写入后 2 秒内的后续读取
if (Date.now() - lastWriteAt < 2000) {
  return await env.DB.prepare("/* primary */ SELECT ...").all();
}

备份

typescript
export async function nightlyBackup(env: Env) {
  const dump = await env.DB.prepare("SELECT * FROM users").all();
  await env.BACKUP_BUCKET.put(
    `backups/${new Date().toISOString().split('T')[0]}/users.json`,
    JSON.stringify(dump.results)
  );
}

局限性

  • 并发写入: 通过单一主库串行化。超过约每秒 200 次写入,就会出现 SQLITE_BUSY 错误。
  • 10 GB 存储上限: 每个数据库的硬限制(约 2000-4000 万行)。
  • 副本延迟: 最终一致性。对敏感操作实现读己之写。
  • 默认无外键: 用 PRAGMA foreign_keys = ON; 开启。
  • SQL 受限: 无存储过程,旧版本无窗口函数。

何时用 D1,何时用替代方案

因素用 D1用 Postgres
读/写比90/10 或更高均衡或写多
数据集大小10 GB 以内任意大小
一致性最终一致性可接受需要强一致
部署Cloudflare Workers任意平台

想要一个在 SaaS 数据库选项之间做选择的完整框架,请看我们的SaaS 数据库架构设计指南。


最佳实践清单

  • 始终使用预处理语句
  • 编写可回滚的迁移
  • 启用 foreign_keys PRAGMA
  • 为 SQLITE_BUSY 实现重试
  • 使用批量操作
  • 尽早创建索引
  • 监控副本延迟
  • 备份到 R2 作为补充
  • 避免 SELECT *——明确指定列
  • 主键使用 UUID

结论

Cloudflare D1 不是 Postgres 的直接替代品。它是一个专为边缘打造的数据库,用写入吞吐和强一致性换取前所未有的读取延迟和边缘运维简单性。

对于写入量适中、用户地理分布广、依赖 Cloudflare Workers 的 SaaS 应用,D1 是一个有说服力的生产选择。但限制是真实的。如果你的应用需要高写入吞吐或复杂的分析查询,请从第一天起就围绕 D1 的约束做设计。要部署基于 D1 的 SaaS 应用,请按我们的TanStack Start 部署指南配置 Cloudflare Workers。