本文参照 Cloudflare 官方手册结构,对 D1 做系统化梳理(数据截至 2026-10,配额/价格以官方最新页面为准)。技术术语保留英文原词以便对照官方资料。
1. 概述
Cloudflare D1 是 Cloudflare 的托管式 Serverless 数据库,提供 SQLite 的 SQL 语义,内建灾难恢复,可通过 Worker 或 HTTP API 访问。它的计费只与「查询 + 存储」相关,且无出网流量费。Free 与 Paid 计划均可用。
一句话定位:基于 SQLite 的 Serverless 关系型数据库,为快速、全球化的查询而生。
2. 核心概念
2.1 SQLite 语义
D1 沿用 SQLite 的 SQL 语法与客户端 API,迁移成本低,你可以用熟悉的 SELECT / INSERT / JOIN / 索引等。
2.2 按行计费(Rows read / Rows written)
- 行读取(rows read):查询扫描了多少行。即使只返回少量结果,全表扫描仍按扫描行数计。
- 行写入(rows written):
INSERT/UPDATE/DELETE影响多少行。 - 行的大小与列数不影响计数;一条 1 KB 和 100 KB 的行都算「1 行」。
- 建索引能大幅降低扫描行数——写入索引列会多写一行(表 + 索引),但通常被读收益抵消。
2.3 Time Travel(时间点恢复)
D1 的备份/恢复机制:可把数据库恢复到过去若干天内的任意一分钟。Free 7 天、Paid 30 天;每库每 10 分钟最多 10 次恢复。
2.4 Global Read Replication(全球读副本)
可添加只读副本,把读查询放到离用户更近的区域,降低延迟、扩展读吞吐。读副本不额外收费,产生的仍是按 rows_read / rows_written 的正常计费。
2.5 Scale-to-zero
不运行查询就不计计算费;只有存储超量才计费。
2.6 为隔离而生的多库
可以零额外成本创建成千上万个数据库用于隔离(例如多租户:每租户一个库)。
3. 架构与工作原理
- D1 由 Cloudflare 托管,无需运维数据库实例。
- 数据库可通过 Worker 的 Binding 访问,也可通过 HTTP API 访问。
- 读副本把数据异步复制到全球,读请求就近命中;写仍走主库。
4. 快速开始
# 1. 创建数据库
wrangler d1 create my-db
# 2. 建表(--local 本地 / 去掉则为远程)
wrangler d1 execute my-db --local --file=./schema.sql
# 3. 在 Worker 中查询(见第 5 节)
wrangler deploy
示例 schema.sql:
CREATE TABLE posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
slug TEXT UNIQUE NOT NULL,
title TEXT NOT NULL,
body TEXT,
created_at INTEGER
);
CREATE INDEX idx_posts_created ON posts(created_at);
5. 使用方式(Worker API)
在 wrangler.jsonc 中绑定:
{
"d1_databases": [
{ "binding": "DB", "database_name": "my-db", "database_id": "<id>" }
]
}
代码中查询:
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
const slug = url.pathname.slice(1);
// 参数化查询,防止注入
const stmt = env.DB.prepare(
"SELECT id, title, body FROM posts WHERE slug = ?"
).bind(slug);
const { results } = await stmt.all(); // 取多行
// const row = await stmt.first(); // 取首行
return Response.json(results);
},
} satisfies ExportedHandler<Env>;
批量写入(batch)可在一个事务里执行多条语句,每条语句仍受单条 SQL 长度等限制约束:
await env.DB.batch([
env.DB.prepare("INSERT INTO posts (slug, title) VALUES (?, ?)").bind("a", "A"),
env.DB.prepare("INSERT INTO posts (slug, title) VALUES (?, ?)").bind("b", "B"),
]);
每次查询返回的
meta对象包含rows_read/rows_written,可用于监控与估费。
6. 配额与限制
| 限制项 | Workers Free | Workers Paid |
|---|---|---|
| 每账户数据库数 | 10 | 50,000(可申请更高) |
| 单库最大容量 | 500 MB | 10 GB |
| 每账户最大存储 | 5 GB | 1 TB(可申请更高) |
| Time Travel 时长 | 7 天 | 30 天 |
| 每 Worker 调用查询数 | 50 | 1,000 |
其他硬性限制(Free/Paid 相同,除非注明):
- 每表最大列数 100;单库行数无上限(受单库容量约束)。
- 单行(字符串 / BLOB / 整行)最大 2 MB。
- 单条 SQL 语句长度上限 100 KB;单次查询绑定参数上限 100;单 SQL 函数参数上限 32;
LIKE/GLOB模式上限 50 字节。 - 单次查询时长上限 30 秒。
- 单脚本绑定资源数约 5,000(不含环境变量/密钥)。
- 文件导入(
d1 execute)上限 5 GB;Time Travel 恢复 10 次 / 10 分钟 / 每库。
7. 定价
| 计费项 | Workers Free | Workers Paid |
|---|---|---|
| 行读取 | 500 万 / 天 | 前 250 亿 / 月包含,超出 $0.001 / 百万行 |
| 行写入 | 10 万 / 天 | 前 5000 万 / 月包含,超出 $1.00 / 百万行 |
| 存储 | 5 GB(账户总计) | 前 5 GB 包含,超出 $0.75 / GB·月 |
- 免费日限额每日 00:00 UTC 重置;月度包含量按订阅日重置。
- 无数据出网(egress)费。
- 超免费日限额后 D1 会拒绝查询并返回超限错误;存储满需清理后才能继续写入/建表/建索引/建触发器。
8. 最佳实践
- 为高频过滤字段建索引,否则全表扫描会让
rows_read蹭上去。 - 列表/分类/标签这类读多写少的查询交给 D1 实时查询 + 边缘缓存,比维护一堆静态列表更省。
- 注意单库 500 MB(Free)/ 10 GB(Paid)上限;大内容(整篇 HTML、媒体)应放到 R2。
- 监控
meta.rows_read/meta.rows_written来估算账单。 - 大批量导入用
d1 execute --file,单次上限 5 GB(文件先传到 R2 再导入)。
9. 适用场景与选型
- 需要 SQL 查询能力的内容/关系型数据:文章、用户、评论、配置、索引。
- 实时列表/聚合查询(配合边缘缓存)。
- 多租户隔离(每租户一个库,零额外成本)。
- 需要强一致的关系数据 → 选 D1;大文件/媒体 → 选 R2;读多写少的全局小配置 → 选 KV。