在线修改MySQL大表的表结构

问题描述

由于某个临时需求,需要给在线MySQL的某个超过千万的表增加一个字段。此表在设计之时完全按照需求实现,并没有多余的保留字段。

我们知道在MySQL中如果要执行ALTER TABLE操作,MySQL会通过制作原来表的一个临时副本来工作。对于表结构的修改在副本上施行,然后将新表替换原始表,此时会产生锁表,用户可以从原始表读取数据,而用户的更新和写入操作都会被lock,待新表准备好后写入新表。
这对于在线的数据量较大的表来说是绝对无法容忍的,并且由于这种在线操作时间会很长,此时如果show processlist,会发现有若干的MySQL进程处于lock状态,当这种进程太多超过单台服务器允许的MySQL进程数,其它进程可能会被拒绝连接。

有哪些方案可以处理这个问题呢?

方案1、直接ALTER TABLE
这个方案只能说这仅仅是一种方案,在某些非实时在线或数据量较小时有较好的表现。

方案2、模拟数据库修改表结构的操作,在非数据库层实现整个过程。

  1. 实现业务中对于数据的读写分离
  2. 创建一个已经按需求修改好结构的新表
  3. 修改业务逻辑,将读操作指向旧表,将写操作指向新表。如果读旧表没有,再读新表,并将旧的数据写入到新表,当然这一步写入操作我们可以不用,我们可以在后台做一个定时任务将旧数据同步到新表。

这种方案有一个较大的缺点,需要业务逻辑层配合实现数据的迁移,对于业务逻辑有修改,并且如果有多台机器的话,需要一台一台的修改,较费时间,但是对于MySQL的两种主要存储引擎都适用。


方案3、facebook online schema change
facebook的OSC在整体流程上与方案2没有较大的区别,只是它在这里引入了触发器,从而不需要修改业务逻辑,在数据库层就实现了新数据的两个表的同步问题。其大概步骤如下:

  1. 按需求创建新表
  2. 针对原始表创建触发器
  3. 对于原始表的更新操作都会被触发器更新到新表中
  4. 把原始表中的数据复制到新表中
  5. 将新表替换旧表

fb的osc方案从数据库层解决了方案2的问题,但是它仅支持InnoDB存储引擎。


方案4、换一个思路,保留字段。
假设一切可以从头再来,我们也许可以加多一些冗余字段,各个类型都加一些,备用。只是,回不去了!

方案5、再换一个思路,增加扩展表。
我们不在原有的表的基础上修改了,以增加扩展表的方式,将新字段的数据写入到扩展表中,修改业务逻辑,这些字段从新表中读取。
志强同学说这是典型的维表结构设计。
暂时解决了问题,如果这些字段后续使用频率高的话,可能会有对后期维护或业务有一定的影响。

后记
基于现有的需求,只是需要记录新的字段,所以采用了扩展表的方案。

在线修改MySQL大表的表结构》上有1条评论

  1. gis_gps

    方案1-3,都用过。用的最多还是方案2
    方案3,当写数据量大的情况下,在ms sql server2005下,会导致数据库死掉.

    回复

gis_gps进行回复 取消回复

电子邮件地址不会被公开。 必填项已用*标注


*

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>