2026-04-01 21:45:28
解决on duplicate key update引发的索引数据不一致问题
问题背景
在使用insert into ... on duplicate key update操作时,TiDB抛出错误码8141,提示索引数据不一致。
错误信息表明事务提交时断言失败,发现本应不存在的key实际存在。
原因排查
复现SQL:通过特定表结构和插入语句复现问题。
观察数据:使用主键和索引分别查询数据,发现主键和索引中的时间字段值不一致。
问题定位:问题与ON UPDATE CURRENT_TIMESTAMP列有关,该列在聚簇主键中未自动更新,但在索引中更新了。
问题分析
现象一:在隐式事务提交(乐观事务)下,更新操作导致索引数据更新但主键未更新,引发数据不一致。提交时因乐观事务的断言检查项差异而报错。
现象二:在显式事务提交(悲观事务)下,批量插入后commit不报错,但后续检查发现数据不一致。需通过调整tidb_txn_assertion_level变量级别在commit阶段提示报错。
触发条件:同时满足以下三个条件会触发该BUG:
表中有ON UPDATE CURRENT_TIMESTAMP列。
该列同时在聚簇索引中。
执行SQL时未显式指定该列,触发自动更新。
问题总结与建议
问题原因:聚簇主键列存在auto update约束时未触发自动更新,导致数据不一致。该问题已在v6.5.3版本修复。
建议:
对于UPDATE语句,手动指定含有ON UPDATE CURRENT_TIMESTAMP条件字段的值,避免主键自动更新。
对于insert into ... on duplicate key update语句,建议改用replace into方式,遇到重复值时执行delete + insert操作,避免使用update。
注意事项
tidb_txn_assertion_level变量在v6.0版本引入,默认为FAST。调至最高级别STRICT可在commit阶段提示报错。
低版本集群原地升级后,该变量可能默认为OFF,需手动调整以确保能发现问题。