-- 为每账号分散刷新增加计划字段。 -- 纯新增列:旧版本二进制忽略这两列,因此回滚程序时不必回滚数据库。 BEGIN; -- next_refresh_at:该子账号下一次应刷新的时刻,Epoch 毫秒。 -- 用整数存时刻,避免 SQLite 文本时间戳被按本地时区解释(实证存在 8 小时偏差)。 -- last_success_epoch:最近一次成功刷新的真实时刻,Epoch 毫秒。 -- 既有的 last_success_at 保持原样,仅供页面展示,不参与调度判断。 ALTER TABLE subscription_account ADD COLUMN next_refresh_at INTEGER; ALTER TABLE subscription_account ADD COLUMN last_success_epoch INTEGER; -- 回填 last_success_epoch:SQLite 的 strftime 把文本时间按 UTC 解释,而 -- CURRENT_TIMESTAMP 写入的正是 UTC,因此这里能得到正确时刻(JDBC 读取则会偏 8 小时)。 -- 必须回填:否则所有既有账号都会被当成「从未成功过」,迁移后立刻集中补刷一遍, -- 正好复现本次改造要消除的爆发。 UPDATE subscription_account SET last_success_epoch = CAST(strftime('%s', last_success_at) AS INTEGER) * 1000 WHERE last_success_epoch IS NULL AND last_success_at IS NOT NULL; -- 已有账号在窗口内按 id 错开,避免迁移后同一 tick 集中开火。 -- 以迁移时刻为基准按 37 分钟步长铺开(12 个账号约 7.4 小时排完)。 UPDATE subscription_account SET next_refresh_at = (CAST(strftime('%s', 'now') AS INTEGER) * 1000) + (id * 37 * 60 * 1000) WHERE next_refresh_at IS NULL; COMMIT;