replace into 后丢失数据

【 TiDB 使用环境】生产环境
【 TiDB 版本】v7.1.2
【复现路径】做过哪些操作出现的问题
【遇到的问题:问题现象及影响】

  1. 现象一。使用golang编程,事务中执行多条 replace into语句,丢数据。sql 如下:
    REPLACE INTO ri_cg_report(tenant, reportid, storeid, pla REPLACE INTO ri_cg_report_info(tenant, reportid, templatei
    REPLACE INTO ri_cg_report_item(tenant, itemid, reportid,
    REPLACE INTO ri_cg_report_item(tenant, itemid, reportid,
    … // 此处省略若干
    REPLACE INTO ri_cg_report_summary_item_relation(tenant, repo REPLACE INTO ri_item_disqualified(tenant, disqualified_id, REPLACE INTO ri_item_disqualified(tenant, disqualified_id`,
    上述事务执行后,应插入4个表共35条记录,但发现第一个表、第二个表没有插入,第三个表缺若干数据,第四个表完整。
    该事务没有报错!

  2. 现象二。在代码中执行 replace into table1 select * from table2 后返回的修改记录数与实际不符,经查,插入数据与实际不符,但也没有报错。

上述两个问题,现象2在版本6的时候出现过几次,升级到7后,截止到目前2个月,还没发生过。现象1刚发现,也不确定之前是否发生过。

不确定是golang的问题,还是tidb的问题。重要的是,它不报错!!!非常头痛。
请问是否有遇到类似问题的朋友,能否给一些排查建议?

【资源配置】进入到 TiDB Dashboard -集群信息 (Cluster Info) -主机(Hosts) 截图此页面

【附件:截图/日志/监控】

直接跑SQL,多跑几次,看能重现不。

你把具体的sql放到数据库客户端执行,看下数据是否丢失,然后来排查是sql问题还是你的代码有问题

1 个赞

修改和插入内容不符,会不会是因为主键有过修改。

数据库端可以临时开启下general log,然后去跑程序。看看general log中的日志,就可以确认这些sql在数据库端执行了还是没有执行。

你插入的表上主键和唯一索引都有吗,只有一个主键没问题,再加个唯一索引就难说了

replace 后边与前边冲突会覆盖的啊,是有可能条数对不上,是不会报错的,你把SQL打出来,手工执行测试下,然后可以建立表把唯一索引去掉,用来找重复数据

程序打日志,将要执行的语句通过日志打出去,比较一下看丢失的是什么数据。

REPLACE 语句在具有主键或唯一约束的表中使用 REPLACE 语句将现有行替换为新的,在没有主键或唯一约束的表中,它的作用方式与 INSERT 语句相同。也可以检查一下数据看是否这个原因导致。

有查出丢哪些数据吗,你最好用个例子复现一下

我的是一个数据同步程序,从mysql binlog同步到tidb,这些sql是在时刻保持运行的

sql本身是没有问题的,它在生产环境持续运行有一段时间了,今天核对数据,偶然发现一笔数据有问题。sql从日志中捞出来重新运行,没发现问题

不是。重新跑一遍,正常

现象2 可能跟 之前 原地更新不加锁的bug 有关

  1. 原地更新值加锁问题:
    INSERT IGNORE 语句和 REPLACE 语句中值重复的 key。在 v6.1.6 之前版本中,这些 key 不加锁。这个问题已在 #42121 修复。https://github.com/pingcap/tidb/issues/36438
    在 UPDATE 语句中值没有改变的唯一索引 key。在 v6.5.2 之前版本中,这些 key 不加锁。这个问题已在 #36438 修复。https://github.com/pingcap/tidb/issues/42121

感谢你的建议!我在程序中执行每条sql前都加了日志,看看是否能复现此问题。
general log我刚试着打开了,每个节点都设置了tidb_general_log=‘on’,却发现并没有生效(日志级别?),晚点再试试

你说的应该是对的,我升级到7.1之后,最近两个月似乎没有发现过这个现象了

刚确认了一下,这个事务中涉及到的表都只有主键,没有其它唯一索引

sql从日志中捞出来执行没有问题。现在我把replace into 改成了 insert into,这样如果是数据问题,事务就会失败。需要再观察一段时间

事务包含40条replace into,分别写入5个表。比较了一下,丢了10条数据,按顺序正好是前10条

有查的。复现。。。挺难的,生产环境,每天100w+,也不敢乱动,调整了一下日志,我再观察一下