meathill
(Meathill Zhai)
2025 年11 月 20 日 13:29
1
我们的数据库是 TiDB Cloud serverless,产品框架 Hono,使用 @drizzle-orm /tidb-serverless + @tidbcloud /serverless 连接数据库。产品部署在 Cloudflare Worker 上面。
之前一切正常,近期(不超过2周)突然遇到 worker memory exceed limits 错误,只有在生产环境上才会稳定复现。因为 Cloudflare Worker 只有 128MB 内存,本地内存比较富裕。经过一段时间的排查(二分切割法),最终基本确定是下面这段代码的问题:
const uid = (
await this.client
.insert(schema.users)
.values({
externalId: externalId,
firstName: firstName,
lastName: lastName,
email: email.toLowerCase(),
})
.$returningId()
)[0];
return uid.id;
将 $returningId() 去掉,然后单独写一个 query 就没问题了。
目前虽然问题已经解决,但我担心是不是没找对地方,所以发出来请教一下大家,看有没有人遇到过类似的问题,或者听说过类似的问题。
1 个赞
TiDB Cloud serverless 结合 drizzle 的 $returningId () 可能在 Worker 中触发内存泄漏。
1 个赞
meathill
(Meathill Zhai)
2026 年1 月 22 日 12:48
14
好像找到了。
因为 TiDB 的 id 不是连续的,所以 $returningId() 的结果是一个巨大的数组,从 1 开始直到一个奇怪的数字(好像也不是最近插入的 id),于是就超了内存。没有办法解决,只能分开,插入一次查询一次。
二分法不错,看起来是Drizzle ORM 的 bug
const result = await this.client.execute(
INSERT INTO users (externalId, firstName, lastName, email) VALUES (?, ?, ?, ?) RETURNING id,
[externalId, firstName, lastName, email]
); 看下爆内存不
我理解你的场景是自增主键的场景
代码在这里:drizzle-orm/drizzle-orm/src/tidb-serverless/session.ts at a086f59fba7f46f3a077893ba912c99e91eaa760 · drizzle-team/drizzle-orm · GitHub
根据这个代码,理论返回的 $returningId() 的数据量是你实际插入行数,不应该是个大数组才对。
但它这里有个 bug,插入多行的时候,除了第一个 id,后续的 id 都可能是错的,因为 tidb cloud id 不一定连续。会不会是后续基于返回的 id 处理的时候导致的问题?
meathill
(Meathill Zhai)
2026 年2 月 3 日 06:59
18
有可能,我没有认真考虑这里,也没有看源码,但是只看返回结果,像是我猜测的那样。
而且这个问题在表小的时候不明显(否则早就测出来了),而是在上线一段时间之后才暴露出来(表内容多了),所以我才做上面的猜测。
如果你插入若干条,实际却返回了极多的 ids, 我觉得可能是产生了溢出导致的。
drizzle-orm 源码遍历 lastInsertId 到 lastInsertId + affectedRows.
但 serverless-js 的 lastInsertId 存在 overflow 的问题:lastInsertId not correct with AUTO_RANDOM id · Issue #65 · tidbcloud/serverless-js · GitHub
你可以检查发生 OOM 时的数据中,id 实际值是否超过 MAX_SAFE_INTEGER,即 9007199254740991.
一个无限循环的例子:
let lastInsertId: number = Number.MAX_SAFE_INTEGER+1;
let rowAffected: number = 5;
let count = 0
for (let i = lastInsertId; i < lastInsertId + rowAffected; i++) {
count = count +1
if (count > 100) {
console.log("stop the loop", count);
break
}
}
块引用
meathill
(Meathill Zhai)
2026 年2 月 3 日 15:21
20
现场已经没有了,不过我印象里不是。
我印象里得到的是数组,[{id: 1}] 开始,结束的 id 不是我插入的 id,比我插入的 id 大,但是大的也不多。