专栏首页数据和云MySQL row格式的两个问题

MySQL row格式的两个问题

作者简介:

刘伟 云和恩墨开源解决方案事业部首席架构师

多年一线互联网企业DBA经历,对MySQL、NoSQL,PostgreSQL等各类开源数据库均有涉猎,负责开发管理过数千实例规模数据库项目,并带领团队开发了MySQL数据库的监控、备份等自动化组件,对超大规模数据库运维平台的开发及管理有丰富经验。

在MySQL的一般场景中,通常我们推荐将复制格式设置为ROW格式,这样所有变更的数据都会被记录到binlog,可以对数据达到最好的保护,万一发生DML误操作,可以直接从binlog恢复数据。

但row格式的设置,会带来许多问题,运维也会相对复杂些。接下来我们通过两个真实的案例说明直接使用row格式复制出现的问题。

1

无索引表导致的延迟问题

原因简述

row格式的binlog event,在执行的时候,对于每一条数据,是通过类似翻译为对应SQL语句的方式逐条执行的。对于UPDATE及DELETE语句,如果表上面没有索引,或者已有索引区分度太低的话,执行速度会非常缓慢。

案例分析

这是我们在为客户排查数据库主从延迟时发现的问题:客户的核心数据库对外提供在线访问,并且应用系统的展示界面是直接读取数据库从库,数据库主从延迟会直接导致页面展示错误,造成经济损失。

在检查到主从同步延迟当时我们使用show slave status命令,(而实际上用心跳表方式更准确),由于业务系统非常重要,多个从库之间延迟严重,为了尽快解决问题,当时使用xtrabackup工具在线备份主库,并替换掉线上从库,暂时解决问题。

但延迟问题本身并没有得到解决。在随后的系统运行中,延迟仍然会产生,于是进行深入检查。

因为客户的binlog_format设置为row,复制进程也只是延迟,show slave status的relay_master_log_file,exec_master_log_pos两个变量一直没有变化,暂时判断为有操作大量数据的DML语句存在。

为了验证,我们解析了对应的binlog日志以及event。但实际结果,对应的event是一个delete event,涉及的数据只有三千多条,这个数量本身的操作并不应该是导致延迟。

然后我们直接查看对应的表结构,以及表的数据量。

mysql create table x ( i int, b varchar(10), v varchar(10), x_type varchar(10), index idx_type (x_type) );

表的数据量也只有几十万条。但是经询问开发人员得知,这个表每小时会插入几千条数据,之后再删除掉某一type的数据,这是表上新添加的规则,结合DBA的说法,这个增删数据的逻辑的导致问题的根源。

解决方法

解决办法有以下几种

1. 创建主键索引。如果目前表内数据本身支持创建唯一或者主键索引,可以直接建立索引解决问题。 2. 创建所有列的联合索引。如果表确实没有办法创建主键或者唯一索引,则尝试对所有列合并添加一个联合索引。 3. 创建部分列的联合索引。由于MySQL索引长度限制,如果确实没有办法创建所有列的索引,找出区分度比较大的几列创建索引。 4. 为表建立自增主键。以上都不能实现的话,为表创建自增id列并设置为主键。这种情况有可能会对应用造成影响,需要预先测试。

实际操作步骤

1. 停止同步。这种情况除了会导致sql延迟,也会导致sql线程持有非常多的行锁,stop slave语句的执行会比较慢需要等待,也可以直接kill掉线程,然后change master切换同步位点到问题event前的位置。 2. 为表加索引或者主键。 3. 启动同步。 4. 观察追上同步。

延伸讨论

MySQL中有一个参数,slave_rows_search_algorithms 可以控制row格式下,mysql执行event时候,搜索对应行的方式。

很多ORM框架由于对MySQL兼容不足,没有针对性的主键索引建立,在row格式下,会出现延迟。但在statement格式复制的情况下,未必会出现类似的问题。

常规建议:如果要使用row格式复制,需要保证自己数据库里面所有的innodb都必须有主键或者唯一键,这样才能避免由于没有合适索引导致的从库延迟问题。

另外,如果开发实用select以及insert语句的时候,都是明确指定列的方式使用的话,可以直接使用解决办法4最简单。这也是很多SQL规范推荐SQL语句需要明确指定列的原因之一。

2

从库alter语句导致同步中断

原因简述

MySQL row格式复制下,主从库之间同一个表如果列的类型不匹配,MySQL会尝试转码,如果转码失败(类型不兼容),则复制中断。

案例分析

问题来源为,客户主从复制中断,SQL线程报错信息为:

Last_SQL_Errno: 1677 Last_SQL_Error: Column 1 of table 'test.t' cannot be converted from type 'varchar' to type 'int'

这个错误明确说MySQL转码失败,询问DBA后,得知之前为了给表添加一列(开发要求列顺序必须为指定顺序):

mysql alter table a add column cl int

DBA试图采用的方式为:

1. 先为从库修改。 2. 在主库设置session的sql_log_off为0,修改从库。

然而执行完第一步后,就发现同步出现错误。直接原因确定为alter语句。经我们询问得知,出于安全考虑,数据库为最近才被修改为row格式,这次给表添加列是DBA在row环境下,初次执行这种类型的DDL语句。

新增的列由于被添加到列顺序中间,导致主库上是字符的列的位置,对应到从库上成了一个数字类型的列,MySQL无法转码,只能报错。

解决方法

  • 最方便的办法,也是最后采用的方法,就是从主库直接xtrabackup备份,之后恢复作为从库提供服务。
  • 另外一个办法是,在从库上把对应表新增的列去掉,重新启动同步。之后找合适的办法进行DDL的执行。

延伸讨论

由于row格式的event里面,只会按照主库的列顺序保存数据,并不会保存列名称,在从库的执行也是按照列顺序对应的,因此,row格式下修改列顺序并不是一个安全行为。

DDL的执行,在MySQL 5.7的时候,基本上都做到了在线改表。但主库在线修改完成之后,从库上的执行也会导致从库延迟,虽然不会阻塞从库的SELECT语句,但延迟本身就很难接受,因此实际情况中,如果无法接受延迟,还是需要考虑pt-osc或者gh-osc工具。

3

总结

MySQL的row格式复制对数据安全的保护,以及主从数据一致的保证是非常重要的,一般来说都建议设置成row格式。在MySQL 5.7之后已经作为复制的默认格式,但带来的运维方式方面的变更,以及对运维手段人员的要求也增高不少,如果需要设置,还是需要多加注意的。

本文分享自微信公众号 - 数据和云(OraNews),作者:刘伟

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2016-12-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Oracle 20c 新特性:Online SecureFiles Defragmentation 在线的 LOB 碎片整理

    墨墨导读:在使用 LOB 的时候,可能大家都遇到过碎片和空间问题的困扰,在 20c 中,Oracle提供了对于 SecureFiles 的碎片整理功能,完善了对...

    数据和云
  • DBA遇到问题时的30 个反应,你是哪一种?

    开发应用程序是一个非常有压力的工作。没有人是完美的,因此在这个行业中,代码中出现 bug 是相当普遍的现象。面对 bug,一些程序员会生气,会沮丧,会心烦意乱,...

    数据和云
  • 升级迁移:利用DMU修改数据库字符集

    何剑敏 Oracle ACS华南区售后团队,首席技术工程师 曾供职于中国联通信息计费部、卓望数码,系统支撑部首席DBA,负责中国移动全网梦网业务和移动应用商城数...

    数据和云
  • 2292: 【POJ Challenge 】永远挑战

    2292: 【POJ Challenge 】永远挑战 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 553 ...

    HansBug
  • 1131: [POI2008]Sta

    1131: [POI2008]Sta Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 783  Solved:...

    HansBug
  • 一条update语句的优化探索(r9笔记第80天)

    今天经开发同学反馈,发现有一些update语句阻塞了部分业务流程,为什么说一些而不是一条,是因为这些update语句都在一个存储过程中,语句结构相仿,真有一种一...

    jeanron100
  • 算法模板——Dinic网络最大流 2

    实现功能:同Dinic网络最大流 1 这个新的想法源于Dinic费用流算法。。。 在费用流算法里面,每次处理一条最短路,是通过spfa的过程中就记录下来,然后顺...

    HansBug
  • 算法模板——Dinic最小费用最大流

    实现功能:输入M,N,S,T;接下来M行输入M条弧的信息(包括起点,终点,流量,单位费用);实现功能是求出以S为源点,T为汇点的网络最大流的最小费用 其实相当的...

    HansBug
  • 1601: [Usaco2008 Oct]灌水

    1601: [Usaco2008 Oct]灌水 Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 1342  S...

    HansBug
  • 算法模板——计算几何2(二维凸包——Andrew算法)

    实现功能:求出二维平面内一对散点的凸包(详见Codevs 1298) 很神奇的算法——先将各个点按坐标排序,然后像我们所知的那样一路左转,求出半边的凸包,然后反...

    HansBug

扫码关注云+社区

领取腾讯云代金券