2 | ALTER TABLE ADD COLUMN報Duplicate entry錯誤 2.1 問題描述 某日系統上線,接到開發小伙伴電話說在上線時,執行一個增加字段的DDL語句腳本時,報錯了,錯誤如下:
ERROR 1062 (23000) at line 1: Duplicate entry 'UR000021426347' for key 'T_CAP_CUST_MIDDLE_INFO_UNIQ_INDEX' 根據錯誤提示的條件去數據庫中查詢卻只能查到一條記錄,并沒有重復記錄。 DDL腳本無法執行,影響后續上線步驟了。 當時由于不在現場,了解到的信息只有:
2.2 原因定位 下面就是到了尋找問題原因的時候了,為什么同樣的DDL語句腳本第一次執行的時候報了Duplicate entry錯誤,第二次卻順利運行了。 其實問題原因很好找,打開Google,輸入關鍵字 mysql alter table add column duplicate entry ,搜索結果中很多關鍵字完全匹配的鏈接,說明很多人遇到過相同問題。 搜索結果中一眼就看到一個鏈接 MySQL Bugs:#76895:Adding new column OR Drop column causes duplicate PK error ,看到MySQL Bug就莫名興奮。 通過該Bug鏈接了解到該問題是Online DDL的一個限制問題,官方認為該問題是一種限制,并不是Bug,所以目前為止還沒有得到解決。
When running an online DDL operation, the thread that runs the ALTER TABLE statement applies an online log of DML operations that were run concurrently on the same table from other connection threads. When the DML operations are applied, it is possible to encounter a duplicate key entry error (ERROR 1062 (23000): Duplicate entry), even if the duplicate entry is only temporary and would be reverted by a later entry in the online log. This is similar to the idea of a foreign key constraint check in InnoDB in which constraints must hold during a transaction. 解釋一下就是當執行Oline DDL操作時,MySQL實際上是將DML緩存(該緩存大小由變量 innodb_online_alter_log_max_size控制,默認128M)起來,等DDL執行完成后再將緩存中的DML重新應用到表上。 如果有別的線程執行了DML操作,在DDL完成后,應用DML時,可能會出現duplicate entry錯誤。
2.3 實驗驗證 上面通過Google找到了理論上可能能解釋問題的原因描述,但是還沒有實際驗證,所以接下來就是線下復現環節。先去找開發同事問了下線上報錯的表只有一種操作 insert into ... on duplicate key... ,且報Duplicate entry的字段上有唯一索引。如果沒有沖突的記錄則插入,否則就更新。那么驗證測試步驟也比較簡單了,找一張測試表,執行ALTER TABLE ADD COLUMN操作,并同時執行insert into...on duplicate key...操作,觀察DDL語句是否會有報錯。
順利的復現了線上的問題現象,那說明當時線上就是因為DML更新了相同的唯一屬性字段鍵值導致DDL執行失敗,報錯。 測試過程中想到insert into... on duplicate key...不行,那么replace into 會不會也一樣導致問題呢,于是就同樣對replace into語句進行了測試。