结论:处理顺序没问题,但段位偏移那段漏了关键细节——UPDATE b_article SET id = id + 1000000 改的是自增主键,MySQL 按索引顺序逐行更新,只要表里原本有 ID ≥ 1000000 的行,偏移过程中就会撞上尚未更新的行,直接报 Duplicate entry。稳妥写法是带 ORDER BY id DESC 让大 ID 先更新,或者分两步(先整体 +2000000,再 -1000000)避开交叉区间。

补充两个容易踩的点:

一是查计数器时,MySQL 8.0 的 information_schema 有缓存,information_schema_stats_expiry 默认 86400 秒,直接 SELECT AUTO_INCREMENT 大概率读到旧值,你会误以为已经修好了。先 SET SESSION information_schema_stats_expiry = 0 再查。另外段位偏移做完,记得把目标表的 AUTO_INCREMENT 手动推到新段位上限之上,不然新插入还是从低位起号。

二是千万级大表不想锁的话,pt-online-schema-change 或 gh-ost 比裸 ALTER TABLE 稳,收尾时它们也会帮你把计数器同步好。

补一句延伸:改库只是第一步,业务代码里硬编码的 ID、Redis 缓存、搜索引擎索引里的主键都得同步刷一遍,这块漏的比数据库本身多。