问题导致的场景,由于业务表为分表,无主键(历史遗留问题),开发偶尔会删除部分异常导入的数据。之前直接删除后导致从延迟,需要很长一段时间长能追上。我们建议两种方法进行数据删除:
> 第一种,写脚本一行行数据删除;
> 第二种,将binlog_format改为statement,然后再进行删除。此操作风险是如果误删除数据会导致数据无法快速恢复。(开发确认后,选择第二种,第一种太复杂,第二种风险可控,数据误删除后可重新导入)
由于选择第二种方式操作,就发生了如下的操作问题,这里在线下模拟了下:
root 17:09: [sbtest]> set session BINLOG_FORMAT = STATEMENT;
Query OK, 0 rows affected (0.00 sec)
root 17:16: [sbtest]> delete from sbtest1 where id in (select id from sbtest2 where id >1000);
ERROR 1665 (HY000): Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.
root 17:16: [sbtest]>
问题原因是目前隔离级别是RC,读提交。当前SQL存在子查询,在RC隔离级别下是有不可复读问题,有可能删除不需要删除的数据,也有可能会导致主从数据不一致。这种情况下,如果要成功删除,有两种办法。
> 第一,将binlog_format改成row
> 第二,将隔离级别改成RR, 目前肯定是选择这种方式,选择第一种又会出现开始的延迟问题。
最后操作方式如下:
root 17:46: [sbtest]> set session BINLOG_FORMAT = STATEMENT;
Query OK, 0 rows affected (0.00 sec)
root 17:48: [sbtest]> set session tx_isolation='REPEATABLE-READ';
Query OK, 0 rows affected (0.00 sec)
root 17:49: [sbtest]> delete from sbtest1 where id in (select id from sbtest2 where id >1000);
Query OK, 0 rows affected (0.09 sec)
文章最后更新时间:
2019年01月15日 17:50:16