阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

MyISAM表加字段的特殊方法

129次阅读
没有评论

共计 2679 个字符,预计需要花费 7 分钟才能阅读完成。

最近一个统计系统的大表需要加字段,表的引擎是 myisam,表大小在 3 亿,物理文件在 106G。想想都蛋疼。那么这种情况下怎么把字段撸上去呢?

1. 首先想到了《高性能 MySQL》提到的直接更改表结构文件(frm),但是在经过测试以后,发现提示表损坏了,需要 repair,只好放弃了。

2. 使用 pt-online-schema-change,刚开始跑没有问题,后面在凌晨发现影响业务了,也只好放弃了。

3. 最近 GitHub 开源的 gh-ost,属于新鲜玩意,还没有研究,只好放弃。

4. 创建新表,load 数据,最后 rename 表。(前提是表只有 insert,表是 myisam 引擎)

最后使用了第四种方案把字段加上了。那么下面就来详细说说第三种方案。

我们假设要把 tb_yayun 表加两个字段,uid,age。

老表(业务在使用的表):

mysql> show create table tb_yayun\G     
*************************** 1. row ***************************
      Table: tb_yayun
Create Table: CREATE TABLE `tb_yayun` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` char(20) DEFAULT NULL,
  `enter_time` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `enter_time` (`enter_time`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

环境准备:

1. 一台空闲的服务器,没跑业务,安装了 mysql 实例的。在该服务器上面创建新表。

mysql> show create table tb_yayun_new\G
*************************** 1. row ***************************
      Table: tb_yayun_new
Create Table: CREATE TABLE `tb_yayun_new` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` char(20) DEFAULT NULL,
  `enter_time` datetime NOT NULL,
  `uid` int(11) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `enter_time` (`enter_time`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

2. 在线上服务器导出 tb_yayun 表的数据(这里有一个技巧,不需要全部导出,截止到某一天就行。)可以用下面下面命令:

mysql -uroot -p -q -s -e “use test;select *,”,” from tb_yayun where enter_time >= ‘2016-08-01 00:00:00′” > /data/tb_yayun.txt

3. 把导出的文件拷贝到上面提到的空闲服务器导入(时间会很长,我当时导入 3 亿的表花了 6 小时):

LOAD DATA INFILE ‘/data/tb_yayun.txt’ INTO TABLE tb_yayun_new;4. 和开发确定一个切换时间;我们的数据都是先入队列,所以是可以暂停一会儿写入的。和开发确定好一个时间以后,比如要在 2016-08-02 15:00:00 以后切换,那么此时还需要做下面工作。还需要补一次数据,因为新表的数据只导入到了 2016-08-01 00:00:00。所以再次从线上服务器导数据。

 mysql -uroot -p -q -s -e “use test;select *,”,” from tb_yayun where enter_time >= ‘2016-08-02 00:00:00’ and enter_time <= ‘2016-08-02 15:00:00’ > /data/02_tb_yayun.txt 再次拷贝到空闲的服务器导入:

 LOAD DATA INFILE ‘/data/02_tb_yayun.txt’ INTO TABLE tb_yayun_new;5. 当导入完成以后,把 tb_yayun_new 表的物理文件拷贝到线上服务器。(MYD,MYI,frm),注意权限。如果线上有 1 主 3 从,那么 4 台服务器都需要拷贝。拷贝完成以后执行 flush tables,然后每台服务器检查表是否正常。limit 一下或者 count 一下都行。

6. 通知开发停止写入,一般是把程序停止一会儿。具体时间不会超过 10 分钟。当开发说已经停了导入数据的程序以后,我们要看看老表是否还有数据写入,对于 myisam 表来说直接 count 看条数是否有变化就行。如果没有数据写入以后。执行下面的命令:

(1)再次从老服务器导数据,我们需要把数据补一致。(线上服务器)

mysql -uroot -p -q -s -e “use test;select *,”,” from tb_yayun where enter_time >= ‘2016-08-02 15:00:00’ > /data/15_tb_yayun.txt(2)load 数据到 tb_yayun_new(注意:会导致从库延时,具体延时多久看导入的数据大小)

LOAD DATA INFILE ‘/data/15_tb_yayun.txt’ INTO TABLE tb_yayun_new;(3)对比新表老表数据是否一致。如果操作没有错误的话,数据肯定是一致的。新表(tb_yayun_new),老表(tb_yayun)进行 count 确认。
(4)老表进行 rename 操作

alter table tb_yayun rename to tb_yayun_old_20160802;(5)新表 rename 操作

alter table tb_yayun_new rename to tb_yayun;

7. 通知开发那边开启数据导入程序。至此大表加字段完成。

总结:

上面提到的方法有非常大的局限性,比如必须是 myisam 表,该表只有 insert,还有就是业务能够忍受 5 -10 分钟没有最新数据。对于前台业务当然无法忍受,不过如果是公司的统计系统,或者内部人员使用。则完全没问题,影响非常小,沟通到位就行。

本文永久更新链接地址 :http://www.linuxidc.com/Linux/2016-09/135590.htm

正文完
星哥说事-微信公众号
post-qrcode
 
星锅
版权声明:本站原创文章,由 星锅 2022-01-22发表,共计2679字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中