← 中文资源

简体中文版本

在线把大表转换为分区表

创建分区孪生表,双写或复制流入,按范围回填,最后在单个事务里短暂换名切换。

阅读英文原文

目标

你锁不住一张要重写的一 TB 大表,但你养得起一个孪生表。在原表旁边建分区副本、用触发器把新写入镜像进去、按月有界回填历史、轮询行数差归零,最后在单个短事务里把两张表换名。排他锁只在最后一刻出现且只持续几毫秒,之前的每一步都可重启。

步骤要点

  1. CREATE TABLE events_p (LIKE events INCLUDING ALL) PARTITION BY RANGE (occurred_at) 建同构分区孪生表。
  2. 建 AFTER INSERT 触发器把新行同步写入孪生表,迁移窗口内旧表照常服务。
  3. 按月建空分区并分批 INSERT 回填,每批事务有界、失败可截断该分区重跑。
  4. 轮询新旧两表 count 差值:触发器持续补新,差值只反映未回填历史,归零即完成。
  5. 换名前先短暂 LOCK 两表,再在单事务内互改表名,排他锁仅毫秒级。

排错提示

旧表历史行会被 UPDATE 时触发器只覆盖 INSERT 是不够的,要么约定窗口期冻结历史变更,要么补上 ON UPDATE OR DELETE 镜像;ATTACH 校验全分区持锁很久,应“先建空分区再填数”或预建约束让校验跳过;主键没包含分区键会直接建不了唯一索引,开工前先把 occurred_at 纳入主键。切换后保留收益立刻兑现:过期即 DROP 一个分区,秒级完成、不再产生表膨胀。

适用边界

双写触发器在整个迁移窗口增加写开销,日程要紧凑、切换后立即摘除;换名仍需短暂排他锁,哪怕只有几毫秒也应避开流量高峰。

代码示例

-- 1. Twin
CREATE TABLE events_p (LIKE events INCLUDING ALL)
  PARTITION BY RANGE (occurred_at);

-- 2. Mirror writes
CREATE TRIGGER events_dw AFTER INSERT ON events
  FOR EACH ROW EXECUTE FUNCTION events_dual_write();

-- 5. Swap in one transaction
BEGIN;
LOCK TABLE events, events_p IN ACCESS EXCLUSIVE MODE;
ALTER TABLE events RENAME TO events_old;
ALTER TABLE events_p RENAME TO events;
COMMIT;