[Performance] 优化 D1 高频查询与写入,支持大规模用户邮箱

Author: dreamhunter2333Created Aug 6, 2026Updated Aug 9, 2026
Labelsenhancement

背景

该 issue 只跟踪已经确认会造成大量 D1 查询或写入的高频热点,不处理邮件解析速度,也不继续加入没有实际需求的接口参数和低频微优化。

已完成

✅ 地址活动时间写入限频(#1104)

  • updateAddressUpdatedAt 仅更新 updated_at 为空或超过 1 天的地址。
  • /user_api/settings 对用户名下地址使用相同的 1 天保活条件。
  • 密码、配置、Passkey counter 和发信计数等真实数据更新不受保活限频影响。
  • 增加 E2E 回归测试,验证一天内重复访问不会重复更新近期地址。
  • 使用固定 1 天窗口,不增加额外环境变量或配置项。

✅ 大用户地址分页与邮件归属查询(#1105)

  • GET /user_api/bind_address 支持 limitoffset 服务端分页;默认返回前 20 条。
  • 用户地址管理页面只请求当前页,不再加载并渲染全部绑定地址。
  • 地址邮件数和发件数只对当前请求页计算。
  • 仅第一页查询总数,后续页面不重复执行总数查询。
  • 用户邮件列表使用数据库 JOIN 校验地址归属,不再加载全部地址并拼接超长 IN (...)
  • 删除用户邮件使用 EXISTS 在数据库侧校验归属。
  • 保留旧地址返回字段并隐藏 password
  • 增加 API 和浏览器 E2E,覆盖分页、字段兼容和跨用户邮件隔离。
  • 更新中英文 CHANGELOG 和 API 文档。

已确认的设计:

  • 不增加后端地址搜索;现有搜索仍由前端处理。
  • 不增加 with_countswith_total 等开关。
  • 地址选择器和用户邮件筛选最多读取前 100 个绑定地址。
  • 不支持一次请求获取全部绑定地址。

待实现

P1:高频清理任务限制扫描量和执行时间

当前定时清理可能扫描或删除全部符合条件的数据,地址关联数据清理还会重复执行相同候选子查询。数据量大时容易占用大量 D1 rows read/write,并导致 Worker 超时。

目标不是单次清空,而是每次快速处理一小批,剩余数据交给后续定时任务。

  • 每种内置清理任务每次只选择固定数量的候选数据,不在同一次请求或定时任务中循环到清空。
  • mailsmails_unknowsendbox 先按已建立索引的 created_at 选取有限 ID,再按 ID 删除。
  • inactiveAddress 使用 updated_at 索引有限选取地址。
  • addressCreatedunboundAddressemptyAddress 先按 created_at 索引缩小候选范围,再使用 NOT EXISTS 做归属或邮件检查。
  • 地址类清理只查询一次本批次的 id/name,后续关联表清理复用这批快照,不再为每张表重复扫描 address。
  • 剩余符合条件的数据留给下一次定时任务;手动清理需要继续时可再次执行。
  • 批次上限使用代码内固定值,不增加环境变量或管理配置。
  • 使用 EXPLAIN QUERY PLAN 确认候选查询使用现有 created_atupdated_ataddressaddress_id 索引,不新增或删除索引。
  • 增加 E2E,验证单次不会超过上限、不会误删,并验证后续执行能够继续处理剩余数据。

实现时不依赖 DELETE ... LIMIT,使用有限候选子查询:

sql
DELETE FROM target_table
WHERE id IN (
  SELECT id
  FROM target_table
  WHERE created_at < datetime('now', ?)
  ORDER BY created_at, id
  LIMIT ?
)

地址类清理先查询一批固定候选,再通过 DB.batch 清理这些地址的关联数据和地址记录。单次批处理结束后立即返回,不继续循环。

暂不实施

以下内容属于低频操作、没有明确收益,或会显著扩大改动范围,不再作为本 issue 的验收要求:

  • 发信计数和历史计数清理优化;当前发信属于低频操作。
  • 邮件解析性能优化。
  • 为邮件列表设计新的元数据表、批量回填旧数据或游标分页。
  • 后端地址搜索以及可选统计参数。
  • 管理员统计合并、Webhook 测试邮件随机查询调整。
  • 地址转移流程重构。
  • saveSetting、request-scope settings 缓存和地址创建返回 ID 等低频微优化。
  • 删除、调整或新增索引。

如果后续监控或真实数据证明这些位置成为高频热点,再分别创建独立 issue。

剩余验收标准

  • 所有内置清理任务都有固定单次候选上限,不执行无界扫描或大删除。
  • 候选查询通过现有索引定位过期数据。
  • 单次清理后允许保留符合条件的数据,后续执行能够继续处理。
  • 地址及关联数据清理不会产生残留或误删。
  • 新增对应 E2E,并更新中英文 CHANGELOG。

Source: dreamhunter2333/cloudflare_temp_email