
文章目錄每日一句正能量1. 背景與問題AUTO_INCREMENT遷移的核心是把“下一個ID由誰生成”遷過去2. 環境與數據先判斷是“簡單自增”還是“分布式編號”2.1 為什么 auto_increment_increment/offset 必須檢查2.2 KingbaseES有兩條主流落地路線方案AIdentity方案BSequence Default3. 復現過程最容易踩的五個坑3.1 坑一導入3億歷史ID后目標生成器仍從1開始3.2 坑二誤以為顯式插入歷史ID會自動同步目標生成器3.3 坑三把主鍵是否連續當成驗收指標3.4 坑四只測試單條INSERT不測試批量主鍵回傳3.5 坑五源庫用多寫AUTO_INCREMENT目標卻按單寫設計4. 方案實施一套可執行的AUTO_INCREMENT遷移步驟4.1 第一步建立主鍵清單4.2 第二步處理 UNSIGNED4.3 第三步優先Identity映射4.4 第四步Sequence兜底方案4.5 第五步全量導數保留原ID4.6 第六步增量同步仍然傳原ID4.7 第七步切流前二次校準生成器4.8 第八步并發回歸單條 INSERT10/50/100并發回滾顯式歷史ID4.9 第九步批量INSERT單獨驗證4.10 第十步ON DUPLICATE KEY UPDATE一起掃描5. 結果對比驗收必須同時看數據、生成器和應用5.1 歷史數據5.2 外鍵和業務引用5.3 生成器安全距離5.4 應用主鍵回傳5.5 示例回歸結果模板5.6 性能指標6. 風險與復盤自增主鍵最危險的是“雙主同時生成”6.1 風險一切換窗口兩邊都在自動生成ID6.2 風險二多庫分片ID被誤當單庫AUTO_INCREMENT6.3 風險三Sequence CACHE造成空洞被誤判數據丟失6.4 風險四歷史高值異常6.5 風險五BIGINT UNSIGNED容量問題6.6 風險六LAST_INSERT_ID依賴被遺漏6.7 風險七Sequence權限遺漏回退方案回源之前也要重新校準AUTO_INCREMENT最終復盤附錄 AMySQL源DDL附錄 BKingbaseES Identity方案附錄 CKingbaseES Sequence方案附錄 D最低回歸清單每日一句正能量“人生沒有標準答案敢于重新開始的人永遠自帶光芒。”每個人都可以書寫自己的答案。而“重新開始”的能力是一個人生命力最璀璨的證明。跌倒后能爬起歸零后能重啟這種勇氣本身就是一種無法被忽視的光芒。主題AUTO_INCREMENT 兼容 / MySQL → KingbaseES / 互聯網業務遷移重點DDL 轉換、Identity/Sequence 選擇、歷史 ID 保留、并發寫入、主鍵回傳、回歸測試、數據校驗與回退適用場景訂單、用戶、支付流水、內容主表、互聯網業務單庫或分片庫遷移。1. 背景與問題AUTO_INCREMENT遷移的核心是把“下一個ID由誰生成”遷過去MySQL 互聯網業務里最常見的主鍵定義之一CREATETABLEbiz_order(order_idBIGINTNOTNULLAUTO_INCREMENT,...PRIMARYKEY(order_id));很多遷移方案會直接寫AUTO_INCREMENT → Identity然后認為工作完成。但自增主鍵真正影響的不是一行 DDL而是一整條寫入鏈路INSERT不傳ID → 數據庫生成ID → 驅動/ORM拿回ID → 子表/消息使用這個ID → CDC傳播 → 下一條記錄繼續生成對互聯網業務還可能存在auto_increment_increment auto_increment_offset 多主寫入 分庫分表 號段 雪花ID 外部ID服務因此遷移前必須先判斷源系統到底是在使用 MySQL 的“單實例 AUTO_INCREMENT”還是借用了 AUTO_INCREMENT 做多寫節點的號段隔離。MySQL 8.4 官方說明InnoDB 為 AUTO_INCREMENT 維護專門計數器不顯式提供值時由計數器產生新值。如果顯式插入的 ID 大于當前計數器后續計數器會被推進。MySQL 同時提供auto_increment_increment和auto_increment_offset可以用于多服務器生成互不沖突的自增值。所以遷移目標必須覆蓋歷史ID不變 目標新ID不沖突 應用主鍵回傳正常 并發寫入安全 多寫架構語義不丟失 異常時能回退2. 環境與數據先判斷是“簡單自增”還是“分布式編號”示例環境源庫MySQL 8.0/8.4 InnoDB 目標KingbaseES V9 業務互聯網訂單服務 單表數據約3億 日新增300萬 主鍵BIGINT AUTO_INCREMENT 寫入方式JDBC/MyBatis源表CREATETABLEbiz_order(order_idBIGINTNOTNULLAUTO_INCREMENT,customer_idBIGINTNOTNULL,order_noVARCHAR(64)NOTNULL,amountDECIMAL(18,2)NOTNULL,created_atDATETIME(6)NOTNULL,PRIMARYKEY(order_id),UNIQUEKEYuk_order_no(order_no));遷移前至少記錄當前MAX(order_id) AUTO_INCREMENT當前起點 數據類型是否UNSIGNED auto_increment_increment auto_increment_offset 主庫數量 是否多主寫 應用如何取得新ID 是否有顯式插入ID邏輯2.1 為什么auto_increment_increment/offset必須檢查MySQL 官方文檔說明auto_increment_increment控制每次自增的步長auto_increment_offset控制起始偏移。比如兩個寫節點節點Aoffset1, increment2 → 1,3,5,7... 節點Boffset2, increment2 → 2,4,6,8...如果這種架構遷移到 KingbaseES 后簡單變成所有節點共用一個 START 1 INCREMENT 1雖然不會一定產生重復但源系統的分布式編號策略已經改變。如果應用或分片邏輯依賴id % 2判斷來源節點就會出現業務問題。因此要先做“主鍵架構識別”。2.2 KingbaseES有兩條主流落地路線當前 KingbaseES SQL 參考明確支持GENERATED ALWAYSASIDENTITYGENERATEDBYDEFAULTASIDENTITYIdentity 列會綁定一個隱式序列新插入行可以自動獲得值。另外 KingbaseES 還提供獨立CREATESEQUENCE支持START WITH INCREMENT BY CACHE NO CYCLE NEXTVAL CURRVAL SETVAL因此最常用兩條路線方案AIdentityorder_idBIGINTGENERATEDBYDEFAULTASIDENTITY適合單寫服務 傳統AUTO_INCREMENT表 希望DDL簡單方案BSequence DefaultCREATESEQUENCE biz_order_id_seq;order_idBIGINTDEFAULTNEXTVAL(biz_order_id_seq)適合需要顯式管理生成器 需要更清楚控制START/INCREMENT/CACHE 遷移工具對Identity支持一般3. 復現過程最容易踩的五個坑3.1 坑一導入3億歷史ID后目標生成器仍從1開始源端MAX(order_id)386,120,008全量遷移order_id原值全部保留目標數據檢查COUNT一致 MAX一致如果 Identity/Sequence 仍然從1開始切流后就有主鍵沖突風險。因此切換前必須滿足目標NEXT VALUE 全局已使用MAX(id)這應該是自動化阻斷條件而不是檢查清單里“人工看一眼”。3.2 坑二誤以為顯式插入歷史ID會自動同步目標生成器MySQL 的行為很容易形成慣性。MySQL 官方示例說明如果向 AUTO_INCREMENT 列顯式寫一個較大的值例如100隨后自動生成的值可以從101繼續。因此 DBA 容易形成“我已經導入了歷史ID目標自增肯定也知道最大值。”但 KingbaseES 的 Identity 依賴隱式序列BY DEFAULT允許顯式歷史值優先不代表遷移程序就可以省略生成器校準。正確做法仍然是導完數據 → SELECT MAX(id) → 檢查Identity/Sequence當前狀態 → 顯式RESTART/SETVAL/ALTER3.3 坑三把主鍵是否連續當成驗收指標MySQL AUTO_INCREMENT 在事務回滾 并發插入 失敗插入 批量語句場景下并不應該被當作業務連續號碼。KingbaseES Sequence 也一樣。官方開發規范明確建議不要將商業邏輯建立在序列完全連續性上并說明增大 CACHE 可以減少爭用但會增加不連續的可能。所以驗收重點是唯一 不會回退到已使用范圍 并發安全不是1001、1002、1003一個都不能少訂單號、發票號如果要求特定連續規則應使用獨立業務編號機制。3.4 坑四只測試單條INSERT不測試批量主鍵回傳MySQL 生態中很多框架依賴LAST_INSERT_ID() getGeneratedKeys() useGeneratedKeysMySQL 官方文檔也明確提供LAST_INSERT_ID()/mysql_insert_id()獲取最近自動生成的 AUTO_INCREMENT 值。遷到 KingbaseES 后數據庫生成 ID 沒問題不代表JDBC MyBatis JPA 批量INSERT都能用完全相同方式拿到主鍵。尤其批量插入INSERTINTO...VALUES(...),(...),(...);不能只假設拿到第一個ID → 后面的ID必然連續推導因為這種假設把“生成器連續性”當成了應用協議。應該讓真實驅動/ORM返回并驗證每個生成主鍵。3.5 坑五源庫用多寫AUTO_INCREMENT目標卻按單寫設計MySQL FAQ 明確說明MySQL 本身沒有通用 Sequence但可以通過auto_increment_increment auto_increment_offset在多服務器場景減少 AUTO_INCREMENT 沖突。如果源系統雙主 多源復制 多機房遷移時必須回答目標還是多寫嗎如果目標變成單主寫可以把主鍵生成收斂到單一 Sequence/Identity。如果目標仍然需要多節點獨立生成ID則要重新設計不同START/OFFSET的Sequence 號段 全局ID服務 雪花ID不能只把源表 DDL 翻譯一下。4. 方案實施一套可執行的AUTO_INCREMENT遷移步驟4.1 第一步建立主鍵清單建議 SQL 清單至少記錄schema table column type unsigned current_max_id auto_increment increment offset foreign_key_count write_qps id_generation_mode分類S1單庫單寫AUTO_INCREMENT S2多寫increment/offset S3分庫分表號段 S4外部ID/雪花 S5業務顯式賦ID優先遷S1復雜度最低。4.2 第二步處理 UNSIGNEDMySQL 常見BIGINTUNSIGNEDAUTO_INCREMENT這不僅是自增問題也是數據類型范圍問題。目標 KingbaseES 如果采用有符號BIGINT必須檢查MAX(id)是否已經超過目標類型上限。大部分業務實際值遠低于上限但遷移評估不能靠猜。必須MAX(id) 未來增長年限做容量評估。4.3 第三步優先Identity映射典型目標CREATETABLEbiz_order(order_idBIGINTGENERATEDBYDEFAULTASIDENTITY(STARTWITH1INCREMENTBY1)PRIMARYKEY,customer_idBIGINTNOTNULL,order_noVARCHAR(64)NOTNULLUNIQUE,amountNUMERIC(18,2)NOTNULL,created_atTIMESTAMP(6)NOTNULL);為什么使用BY DEFAULT而不是遷移階段直接ALWAYSKingbaseES 官方語義是BY DEFAULT 用戶顯式提供值時用戶值優先 ALWAYS 默認強制使用生成值除非顯式覆蓋系統值遷移全量和增量都需要保留 MySQL 歷史 ID因此BY DEFAULT更方便。切換完成后是否調整更嚴格的寫入策略可以通過應用層禁止傳ID 權限 SQL審計實現。4.4 第四步Sequence兜底方案如果想把生成器獨立出來CREATESEQUENCE biz_order_id_seqASBIGINTSTARTWITH386120009INCREMENTBY1CACHE100NOCYCLE;列order_idBIGINTDEFAULTNEXTVAL(biz_order_id_seq)KingbaseES 官方序列文檔明確支持START WITH、INCREMENT BY、CACHE、NO CYCLE并可通過nextval/currval/setval管理生成器。Sequence 方案的工程優勢生成器獨立可見 參數更容易審計 多表/特殊生成策略可重用 遷移腳本容易校準缺點DDL比Identity多一個對象 權限要單獨確認 對象命名和生命周期要治理4.5 第五步全量導數保留原ID歷史訂單1 2 ... 386120008目標必須仍然是1 2 ... 386120008不要重新生成。原因order_detail.order_id payment.order_id message業務鍵 數據倉庫引用 日志關聯都可能已經依賴原ID。如果重新編號就會把“主表遷移”變成“全鏈路主鍵重映射項目”。4.6 第六步增量同步仍然傳原ID全量遷移運行幾個小時甚至幾天時MySQL 仍有新訂單寫入。CDC 增量INSERT order_id386120009目標也要INSERT order_id386120009而不是由 KingbaseES 自己生成一個 ID。遷移期MySQL是主鍵權威切流后KingbaseES才成為新的主鍵權威這個切換點必須明確。4.7 第七步切流前二次校準生成器第一次全量導完MAX(id)386120008幾小時后 CDC 已經追到386520100所以不能只在全量后校準一次。切流正確順序停止源端新寫 ↓ 追平最后CDC ↓ 源目標MAX(id)比對 ↓ 目標生成器再次校準 ↓ 驗證NEXT VALUE安全 ↓ 開啟KingbaseES寫4.8 第八步并發回歸至少測試單條 INSERTINSERTINTObiz_order(customer_id,order_no,amount)VALUES(...);斷言生成ID非NULL 數據庫行ID 應用拿到ID10/50/100并發檢查duplicate0 PK conflict0 generated ids unique回滾BEGIN INSERT ROLLBACK允許ID出現空洞但后續不得產生重復。顯式歷史ID分別插入比當前MAX低 比當前MAX高確認遷移流程和后續校準腳本都能正確處理。4.9 第九步批量INSERT單獨驗證MySQL 應用很喜歡INSERTINTOt(...)VALUES(...),(...),(...);遷移后至少驗證生成多少個ID 驅動返回多少個 順序是否對應輸入行 批次部分失敗如何處理不要用first_id i推算后續主鍵作為正式設計。4.10 第十步ON DUPLICATE KEY UPDATE一起掃描互聯網 MySQL 常見INSERT...ONDUPLICATEKEYUPDATE...MySQL 官方文檔說明它遇到 UNIQUE/PRIMARY KEY 沖突時可以轉為 UPDATE在含 AUTO_INCREMENT 的表上它還會影響自增值和LAST_INSERT_ID()相關行為。因此遷移自增主鍵時應該順便掃描ON DUPLICATE KEY UPDATE REPLACE INTO INSERT IGNORE LAST_INSERT_ID這些都屬于“寫入語義”不能只改表結構。5. 結果對比驗收必須同時看數據、生成器和應用5.1 歷史數據至少比較COUNT(*)MIN(id)MAX(id)COUNT(DISTINCTid)斷言COUNT COUNT(DISTINCT id)主鍵無重復。5.2 外鍵和業務引用例如SELECTCOUNT(*)FROMorder_detail dLEFTJOINbiz_order oONd.order_ido.order_idWHEREo.order_idISNULL;結果05.3 生成器安全距離遷移完成MAX(id)386520100目標下一值必須386520100如果采用多節點號段還要驗證所有節點未來生成空間互不沖突5.4 應用主鍵回傳測試JDBC getGeneratedKeys MyBatis useGeneratedKeys JPA GeneratedValue 批量Insert 事務Insert必須斷言應用對象ID 數據庫實際ID5.5 示例回歸結果模板用例MySQLKingbaseES結果單條自動ID成功成功通過顯式歷史ID保留保留通過50并發無重復無重復通過ROLLBACK后繼續插入允許空洞允許空洞通過JDBC取主鍵正常正常通過批量Insert返回ID已驗證返回通過這些是驗收模板不是本文聲稱的真實生產結果。5.6 性能指標自增遷移還應該記錄Insert TPS P50/P95/P99 生成器等待 WAL 索引寫入 Sequence CACHE大小KingbaseES 官方開發規范建議適當增大 Sequence CACHE 可以降低爭用但同時會增加序列不連續性。互聯網高并發業務可以測試CACHE 1 CACHE 20 CACHE 100 CACHE 300選擇性能和可接受空洞之間的平衡。再次強調主鍵唯一遠比主鍵連續重要。6. 風險與復盤自增主鍵最危險的是“雙主同時生成”6.1 風險一切換窗口兩邊都在自動生成ID這是最大的風險。如果MySQL繼續AUTO_INCREMENT KingbaseES Identity也開放兩個庫可能在相同數值空間生成新ID。所以切換要保證同一個業務主鍵空間在任意時刻只能有一個權威生成器除非已經設計了明確不沖突的號段。6.2 風險二多庫分片ID被誤當單庫AUTO_INCREMENT比如db0 → 奇數 db1 → 偶數或者每個分片從不同億級號段開始這些信息可能根本不在表 DDL 中而在MySQL系統變量 部署配置 中間件 應用代碼遷移清單必須覆蓋數據庫外部。6.3 風險三Sequence CACHE造成空洞被誤判數據丟失KingbaseES 官方文檔說明緩存序列號能提升性能但實例異常關閉時緩存中尚未使用的值可能被跳過。這不是訂單丟失。真正的訂單完整性應該通過業務唯一鍵 記錄數 狀態 消息鏈路判斷。不要用ID必須連續做數據完整性校驗。6.4 風險四歷史高值異常可能絕大多數id 4億但曾經人工修復id9,000,000,000如果只按“正常增長趨勢”設置目標序列4億1最終仍會撞到歷史記錄。所以必須讀取真實MAX(id)6.5 風險五BIGINT UNSIGNED容量問題如果 MySQL 使用BIGINT UNSIGNED目標類型范圍可能不同。即使當前數據沒超過范圍也要評估未來3年/5年增長不能等遷移后幾年才發現主鍵逼近上限。6.6 風險六LAST_INSERT_ID依賴被遺漏應用可能直接執行SELECTLAST_INSERT_ID();MySQL 官方說明LAST_INSERT_ID()對當前連接生成的 AUTO_INCREMENT 值有明確語義。遷移后不能假設這個函數和連接態語義仍然完全一樣。更推薦應用通過目標驅動支持的generated keys RETURNING獲取新主鍵并做真實連接池測試。6.7 風險七Sequence權限遺漏如果用Sequence Default應用賬號除了表 INSERT 權限還需要確認能夠正常訪問相關序列。這種權限問題往往在DBA賬號測試成功 生產應用賬號失敗時才暴露。切換清單要使用真實應用賬號執行。回退方案回源之前也要重新校準AUTO_INCREMENT假設MySQL最后ID 386520100切到 KingbaseES 后又寫了50000條最大 ID 已經386570100現在因為應用兼容問題需要回退 MySQL。不能簡單把連接串切回MySQL否則 MySQL 原計數器可能繼續從386520101生成而 KingbaseES 窗口期已經使用了這些 ID。正確回退1. 停止KingbaseES新寫 2. 固化目標最后ID和業務水位 3. 將目標新增記錄反向同步MySQL并保留原ID 4. 校驗兩端MAX(id) 5. 將MySQL AUTO_INCREMENT推進到全局MAX(id)安全步長 6. 恢復MySQL寫入口 7. KingbaseES轉為只讀排障回退原則和切流原則其實完全一致下一任主庫的主鍵生成器必須位于所有已使用ID之后。最終復盤MySQL 到 KingbaseES 的 AUTO_INCREMENT 遷移建議按五層處理第一層識別源編號架構 AUTO_INCREMENT / incrementoffset / 分片 / 外部ID 第二層選擇目標生成器 Identity / Sequence / 外部ID服務 第三層保留歷史主鍵 全量 CDC 都顯式傳原ID 第四層校準生成器 NEXT VALUE 全局MAX(id) 第五層回歸與回退 并發寫 主鍵回傳 雙端水位 回源校準如果只記住一句話AUTO_INCREMENT 遷移不是把關鍵字換掉而是在遷移“誰擁有下一個唯一ID的生成權”。這個生成權只要在切換窗口中模糊一秒就可能留下后續非常難修復的主鍵沖突。附錄 AMySQL源DDLCREATETABLEbiz_order(order_idBIGINTNOTNULLAUTO_INCREMENT,customer_idBIGINTNOTNULL,order_noVARCHAR(64)NOTNULL,amountDECIMAL(18,2)NOTNULL,PRIMARYKEY(order_id));附錄 BKingbaseES Identity方案CREATETABLEbiz_order(order_idBIGINTGENERATEDBYDEFAULTASIDENTITY(STARTWITH1INCREMENTBY1)PRIMARYKEY,customer_idBIGINTNOTNULL,order_noVARCHAR(64)NOTNULL,amountNUMERIC(18,2)NOTNULL);附錄 CKingbaseES Sequence方案CREATESEQUENCE biz_order_id_seqASBIGINTSTARTWITH386520101INCREMENTBY1CACHE100NOCYCLE;CREATETABLEbiz_order(order_idBIGINTPRIMARYKEYDEFAULTNEXTVAL(biz_order_id_seq),...);附錄 D最低回歸清單[ ] AUTO_INCREMENT列已全部掃描 [ ] 當前MAX(id)已記錄 [ ] increment/offset已記錄 [ ] UNSIGNED范圍已評估 [ ] 分庫分表/外部ID邏輯已識別 [ ] 全量導入保留原ID [ ] CDC保留原ID [ ] 目標生成器已二次校準 [ ] 單條INSERT主鍵回傳通過 [ ] 批量INSERT主鍵回傳通過 [ ] 10/50/100并發無重復 [ ] 回滾后寫入通過 [ ] 應用真實賬號權限通過 [ ] 回退AUTO_INCREMENT校準腳本已演練轉載自https://blog.csdn.net/u014727709/article/details/163728579歡迎 點贊?評論?收藏歡迎指正