MyISAM表加字段的特殊方法

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

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

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

3. 创建新表,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分钟没有最新数据。对于前台业务当然无法忍受,不过如果是公司的统计系统,或者内部人员使用。则完全没问题,影响非常小,沟通到位就行。

时间: 2024-10-12 19:03:39

MyISAM表加字段的特殊方法的相关文章

获取sqlserver数据库中所有库、表、字段名的方法

1.获取所有数据库名: SELECT Name from Master..SysDatabases ORDER BY Name 2.获取所有表名: SELECT Name from DatabaseName..SysObjects Where XType='U' ORDER BY Name XType='U':表示所有用户表; XType='S':表示所有系统表; 3.获取所有字段名: SELECT Name from SysColumns WHERE id=Object_Id('TableNa

批量给数据库表加字段

declare @tablename varchar(50) ,@sql varchar(1000) ,@dbname varchar(50) set @dbname=DB_NAME() declare addcolumn_Cusor cursor for select name from sys.tables open addcolumn_Cusor fetch next from addcolumn_Cusor into @tablename while(@@fetch_status=0)

AX 2012 现有量表加字段

参考: 1.https://community.dynamics.com/ax/f/microsoft-dynamics-ax-forum/105963/adding-fields-to-inventonhand-form-in-ax2012 2.https://community.dynamics.com/ax/b/technicaltutorialsformsdynamicsax2012/posts/how-to-add-field-in-onhand-inventory-form-in-a

06 | 全局锁和表锁 :给表加个字段怎么有这么多阻碍?

今天我要跟你聊聊MySQL的锁.数据库锁设计的初衷是处理并发问题.作为多用户共享的资源,当出现并发访问的时候,数据库需要合理地控制资源的访问规则.而锁就是用来实现这些访问规则的重要数据结构. 根据加锁的范围,MySQL里面的锁大致可以分成全局锁.表级锁和行锁三类.今天这篇文章,我会和你分享全局锁和表级锁.而关于行锁的内容,我会留着在下一篇文章中再和你详细介绍. 这里需要说明的是,锁的设计比较复杂,这两篇文章不会涉及锁的具体实现细节,主要介绍的是碰到锁时的现象和其背后的原理. 全局锁 顾名思义,全

MySQL中大数据表增加字段,通过增加索引实现

MySQL中大数据表增加字段,通过增加索引实现 普通的添加字段sql ALTER TABLE `table_name` ADD COLUMN `num` int(10) NOT NULL DEFAULT 0 AFTER `addtime`; 普通的添加索引sql ALTER TABLE `table_name` ADD INDEX `num` (`num`) ; 但是线上的一张表如果数据量很大呢,执行加字段操作就会锁表,这个过程可能需要很长时间甚至导致服务崩溃,那么这样操作就很有风险了. 在网上

b/s和C/S方法用C#递归方法把数据表加载到treeview控件中

先看一下数据库的结构: 表结构如下所示: Num                   Name                                 fatherNum       BZ 01                      总节点                                      0              ...... 0101                   第一个一级节点                          01      

MyISAM表的.frm文件丢失后的恢复方法

MyISAM表的.frm文件丢失后的恢复方法: 1.创建实验用的MyISAM表t1,并插入数据: mysql> create table t1(id int) engine=myisam; Query OK, 0 rows affected (0.01 sec) mysql> insert into t1 values(1),(2),(3),(4),(5),(6),(7),(8); Query OK, 8 rows affected (0.00 sec) Records: 8  Duplica

Oracle、Mysql、SqlServer创建表和给表和字段加注释

一.Oracle --创建表 create table test ( id varchar2(200) primary key not null, sort number, name varchar(200) ) --字段加注释 comment on column test.id is 'id'; comment on column test.sort is '序号'; --表加注释 comment on table test is '测试表'  二.Mysql --创建表 create tab

MariaDB 10.3 instant ADD COLUMN亿级大表毫秒级加字段

加字段是痛苦的,需要对表进行重建,尤其是对亿级别的大表,虽然Online DDL可以避免锁表,但如果在主库上执行耗时30分钟,那么再复制到从库上执行,主从复制就出现延迟.使用instant ADD COLUMN特性,只需弹下烟灰的时间,字段就加好了,享受MongoDB那样的非结构化存储的灵活方便. 限制1.如果指定了AFTER,字段必须是在最后一列,否则会重新建立表2.不适用于ROW_FORMAT = COMPRESSED3.DROP COLUMN需要重建表 原文地址:http://blog.5