feat: S0 主键改雪花(DDL 去 identity + 实体 ASSIGN_ID + 雪花配置)

为什么:自增主键把 ID 分配锁在单库序列上,分库分表时无法横向扩展。趁线上业务数据
近零(只有系统种子表有量)先改,代价最低。

- sql/schema.sql、sql/schema-phase1.sql、sql/partition-maintenance.sql:61 处
  GENERATED BY DEFAULT AS IDENTITY 去掉,主键改 BIGINT 无默认值
- 52 个实体 @TableId IdType.AUTO -> IdType.ASSIGN_ID;两个入口 id-type: assign_id,
  并加 global-config.sequence.worker-id/datacenter-id(单机固定值,多实例需按实例分配)
- 新增 sql/migrate-s0-snowflake.sql:存量库幂等迁移,走 DROP IDENTITY 保留数据,不重建表
- 实测:三份建表脚本在新库连跑两遍幂等;线上 57 张表 identity 归零;
  watch_history/playback_ticket/order_event 的主键与唯一索引仍含分区键
This commit is contained in:
Vicky committed 2026-10-16 09:00:38 +08:00
1 parent 6833e01e1f
commit 37c9a141d3
58 files changed
+174 -115

No files matched your search

+49
View File
@@ -0,0 +1,49 @@
-- Author: fruit.com.cn
--
-- S0 主键改雪花 · 存量库迁移(PostgreSQL 18)
--
-- 背景:第一阶段建表用的是 GENERATED BY DEFAULT AS IDENTITY(数据库自增序列),
-- 这会让 ID 分配集中在单库的序列上,一旦分库分表就无法横向扩展。
-- S0 把主键改成应用侧雪花 ID(MyBatis-Plus IdType.ASSIGN_ID),
-- DDL 侧只需要把 identity 去掉——序列不再需要。
--
-- 本脚本只做一件事:把所有 identity 列改成普通 BIGINT(**保留已有数据,不重建表**)。
-- 刻意不用 DROP TABLE / TRUNCATE,避免误伤存量数据。
-- 幂等:已经迁移过的库再跑一遍不做任何改动,NOTICE 里的数字会是 0。
--
-- 执行:psql -h 127.0.0.1 -U fruitshorts -d fruitshorts -f sql/migrate-s0-snowflake.sql
-- 复查:脚本末尾的注释 SQL(改写后应返回 0 行)
DO $$
DECLARE
r record;
v_done int := 0;
BEGIN
-- relispartition = false 表示"只处理顶层表":
-- 分区父表在 pg_class 里 relkind = 'p',月分区子表 relispartition = true;
-- identity 定义在父表上,子表跟着继承,所以逐个改子表是多余的。
FOR r IN
SELECT c.oid::regclass AS tbl, a.attname AS col
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
JOIN pg_attribute a ON a.attrelid = c.oid
WHERE n.nspname = 'public'
AND c.relkind IN ('r', 'p')
AND c.relispartition = false
AND a.attidentity <> ''
AND a.attnum > 0
ORDER BY c.relname
LOOP
EXECUTE format('ALTER TABLE %s ALTER COLUMN %I DROP IDENTITY IF EXISTS', r.tbl, r.col);
v_done := v_done + 1;
END LOOP;
RAISE NOTICE 'S0 迁移完成:处理 % 个 identity 列(重复执行时为 0)', v_done;
END $$;
-- 复查用(结果应为 0 行):
-- SELECT c.relname, a.attname
-- FROM pg_class c
-- JOIN pg_namespace n ON n.oid = c.relnamespace
-- JOIN pg_attribute a ON a.attrelid = c.oid
-- WHERE n.nspname = 'public' AND a.attidentity <> ''
-- ORDER BY 1, 2;