Cloudflare 的 D1 是很多个人项目在用的免费数据库:SQLite 兼容、跟着 Workers 跑在边缘,给博客存评论、给玩具项目存数据都很顺手。9 月 1 日起,它的免费额度开始被真正执行了。
额度本身没动:Workers Free 套餐下,每天 500 万行读、10 万行写,账号总存储 5GB,单库上限 500MB。变的是超了之后的行为——以前偶尔会「放你过去」,现在 Workers 的 Binding API 和 REST API 都会明确返回错误,一直持续到 UTC 次日零点重置。换算到国内时间,就是每天早上 8 点恢复。
后果也很直接:数据一条都不会丢,但你的应用查不动它,对外表现出来就是站点停摆。
这是我觉得最该单独拎出来讲的一点。
D1 计费里的「行读」,统计的不是你的查询返回了多少行,而是数据库引擎为了得出这个结果不得不检查了多少行。一张 5000 行的表,跑一次 SELECT * FROM t 这种全表扫描,就是 5000 行读——哪怕最后只命中一条记录。跑 1000 次,当天额度就没了。
关键点是:索引不是优化项,它是配额保护。 官方文档里给的定义很朴素:没索引的过滤条件,数据库必须先扫描更多行才能确定该返回哪些。而公开的案例把它讲得更狠——有人在 D1 上跑分析看板,四个聚合查询把月账单推到 134 美元,最贵的那条是没加索引的 SELECT MAX(year),每天被调用 22.5 万次、累计扫描了 172 亿行。补一个索引之后,账单掉了 95%。
这件事的重量在于:免费额度并不是「给得太少」,而是你可能在完全不知道的地方,按扫描倍数把额度消耗掉了。
第一,看清哪些查询在扫表。 拿 EXPLAIN QUERY PLAN 过一遍最常被调用的语句:结果里出现 SCAN table,就是没走索引;想看到的是 SEARCH table USING INDEX。
第二,该加的索引加上。 过滤、JOIN、GROUP BY 用到的列是重点,多个条件一起用就上复合索引。同时记住两个反向细节:索引本身会增加写入量(CREATE INDEX 也算一次写),而 Cloudflare 面板和 wrangler 里手动执行的查询同样计入用量——别在生产库里直接跑大查询排查问题。
第三,把用量盯起来。 D1 的 meta 对象、GraphQL Analytics API,或者面板里数据库的 Metrics → Row Metrics,都能看到真实的消耗曲线。免费额度的重置点是 UTC 零点,也就是北京时间早上 8 点——这意味着额度被打满最可能撞上国内访问的早高峰。晚上出问题少,早上炸的概率高。
我的判断是:纯静态博客基本碰不到这条规则。Astro 生成的页面本身不查库,如果 D1 只用来存评论、点赞,一天几十万行读都用不到。
真正危险的是「每次请求都跑一次聚合」的写法:首页显示总浏览量、排行榜、评论计数、最近热度,只要落在没索引的列上,就会被放大成扫描量,再乘上每天的访问次数。对这类需求,更稳的做法是能静态就静态、能缓存就缓存——浏览量这种数字更适合放进 KV 或分析服务,而不是每次请求都去 SELECT COUNT(*) 一遍。
Workers Paid 每月 5 美元,D1 侧包含每月 250 亿行读、5000 万行写,超出后每百万行读 0.001 美元、每百万行写 1 美元,存储每 GB 每月 0.75 美元。
真正值得注意的不是这些数字的大小,而是超额之后的两条路完全不同:免费档是报错停服、不会产生账单;付费档是继续跑、自动计费。
我不觉得这算涨价。它更像是 Cloudflare 把「免费额度是一句硬承诺」这件事坐实了:好处是你的小站不会因为被人刷流量而收到天价账单;坏处同样实在——被刷的时候,站会直接停,没有缓冲、也没有降级。
所以我认为,比「要不要升级付费」更值得先做的事,是给应用留一条数据库不可用时的降级路径:缓存兜底、静态兜底,或者干脆让核心页面不依赖数据库。另外要认清一个趋势:这个月 Cloudflare 一边收紧免费额度,一边把 Workers 的打包上限从压缩 3MB/10MB 提到 64MiB(不分套餐)。一手收紧资源消耗,一手放宽技术限制,是同一盘棋——免费让你把原型跑通,一旦进入生产规模,账单就该换你来扛。对个人项目来说,这不是坏消息,前提是你别把没索引的查询留在生产环境里。 (内容由AI生成,仅供参考)
正在加载评论...