Online DDL工具的安装与使用
最近经常在线上经常遇到有性能问题的SQL,有些表没有合理添加索引,有些表添加的索引不合理,各种各样的问题,导致SQL的执行效率不高。这时DBA们不得不重构SQL,使其达到最好的性能,这时我们往往要在线添加或者删除索引、字段等等的操作。如果是MySQL 5.5的版本在DDL方面是要付出代价的,虽然已经有了Fast index Creation,但是在添加字段还是会锁表的,而且在添加删除辅助索引是会加S锁,也就是无法进行写操作。所以,这里就有相关工具的出现,那就是pt-online-schema-change和oak-online-alter-table,都实现了Online DDL,但是每个工具都有相应自己的限制。如果是MySQL5.6以及更高的版本,已经开始支持Online DDL,我们下面的研究,针对MySQL5.6之前的版本。
主要介绍两个工具:oak-online-alter-table & pt-online-schema-change
一、oak-online-alter-table安装及使用
openark工具包是一组用于MySQL的实用工具,该工具集解决日常维护任务,这些工作比较复杂和耗时。其中oak-online-alter-table就是该工具集中的一个工具,该工具执行非阻塞ALTER TABLE的操作。当然还有其他的工具,有关openark工具说明可以参考http://code.openark.org/forge/openark-kit
1)安装openark工具包(安装依赖)
[root@xuanzhi-mysql ~]# yum install python-mysqldb MySQL-python -y
2)openark软件包下载:(一般只有海外服务器才可以直接在服务器上下载,下载个包相信难不了大家的)
[root@xuanzhi-mysql ~]# wget https://openarkkit.googlecode.com/files/openark-kit-196-1.noarch.rpm
3)openark的安装:
[root@xuanzhi-mysql ~]# rpm -ivh openark-kit--.noarch.rpm
Preparing... ########################################### [%]
:openark-kit ########################################### [%]
[root@xuanzhi-mysql ~]#
该工具提供了以下三种基本功能:
1、一个非阻塞ALTER TABLE操作,以下几种情况都是支持的
1)添加列 (新列必须有一个默认值)
2)删除列 (旧表必须有一个单列的唯一索引)
3)修改列 (改变字段类型,包括唯一键的列)
4)添加索引 (普通索引,唯一索引,全文索引)
5)删除索引(旧表必须有一个单列的唯一索引)
6) 修改表引擎:当处理非事务性引擎应该格外注意
7)添加外键约束
2、(可能会在未来版本不再支持):创建一个镜像表,与原始表同步,只要不发生如下操作:
1)对原始表ALTER TABLE操作
2)对原始表TRUNCATE操作
3)使用LOAD DATA INFILE向原始表导入数据
4)对原始表OPTIMIZE TABLE操作
3、一个空的ALTER,重建一个表:释放磁盘空间和重新组织表,相当于优化表。
oak-online-alter-table的一些使用限制进行说明:
1、在该表上面至少有一个单列的UNIQUE KEY
2、更改原始表为单个字段的唯一索引
3、该表没有定义触发器“AFTER”(oak会自己创建触发器)
4、应该没有外键约束(FOREIGN KEY)
5、表名长度不超过57个字符
oak-online-alter-table的工作原理:
该工具运行时,它允许INSERT,UPDATE,DELETE,REPLACE原始表,但是不允许TRUNCATE,ALTER,REPAIR OPTIMIZE或者其他方式对原表进行操作。该工具适用于InnoDB表,MyISAM表,或以其他任何表级锁的存储引擎(MEMORY, ARCHIVE)。该工具工作原理是创建一个镜像表的同时,它慢慢与原始表同步。直到同步完成,要做到这一点,该工具必须在原始表创建AFTER INSERT, AFTER UPDATE, AFTER DELETE触发器。镜像表与原始表同步发生在几个步骤。在这些步骤中,数据被从原始表复制到镜像表。这是以行块进行,这个大小是可以用chunk-size选项配置的。当一个块被复制,在(MyISAM,ARCHIVE,MEMORY)存储引擎上有读锁,或包含在该块上面的行记录(innodb),较小的块——更快的锁被移除,允许更大的并发性。对于写密集型应用,它可能是可取的,允许对块之间的停顿,以使尽可能减少影响。这可以使用sleep-ratio选项进行配置。而块之间停顿时没有被加锁。即便如此,对性能的影响是在运行应用程序时,这是由于触发器被添加到表上和DML语句在向镜像表同步。它需要有足够的磁盘空间来容纳改变的表(如一个正常的ALTER TABLE)。在操作完成时才出现磁盘空间恢复(取决于你的存储引擎和配置)。
测试如下:
1、添加一个字段
[root@xuanzhi-mysql ~]# oak-online-alter-table -uroot -p123456 -S /data/mysql-5.5./mysql.sock --table=sakila.film --alter="ADD COLUMN name VARCHAR(64) DEFAULT ''"
-- Connecting to MySQL
-- Table sakila.film is of engine innodb
-- ERROR: Errors found. Initiating cleanup
-- Tables unlocked
-- ERROR: Table must not have any 'AFTER' triggers defined.
[root@xuanzhi-mysql ~]#
很明显提示有触发器,也是上面提到的使用限制。
[root@xuanzhi-mysql ~]# oak-online-alter-table -uroot -p123456 -S /data/mysql-5.5./mysql.sock --table=sakila.actor --alter="ADD COLUMN name VARCHAR(64) DEFAULT ''"
-- Connecting to MySQL
-- Table sakila.actor is of engine innodb
-- ERROR: Errors found. Initiating cleanup
-- Tables unlocked
-- ERROR: Table must not have any foreign keys defined (neither as parent nor child).
提示了有外键约束,无论是父表还是子表 ,如果有外键的话,都是不允许添加字段的。
下面给t1表添加一个辅助索引看看
mysql> show create table t1\G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`id` int(11) DEFAULT NULL,
`name` char(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec) mysql>
在name字段添加普通索引:
[root@xuanzhi-mysql ~]# oak-online-alter-table -uroot -p123456 -S /data/mysql-5.5./mysql.sock --table=sakila.t1 --alter="ADD KEY(name)"
-- Connecting to MySQL
-- Table sakila.t1 is of engine innodb
-- Checking for UNIQUE columns on sakila.t1, by which to chunk
-- Possible UNIQUE KEY column names in sakila.t1:
-- ERROR: Errors found. Initiating cleanup
-- Tables unlocked
-- ERROR: Table must have a UNIQUE KEY on a single column
[root@xuanzhi-mysql ~]#
可以看到提示说没有唯一键,也是上面提及到的使用限制。我们添加一个唯一键再看看:
mysql> alter table t1 add unique key (id);
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0 mysql>
[root@xuanzhi-mysql ~]# oak-online-alter-table -uroot -p123456 -S /data/mysql-5.5./mysql.sock --table=sakila.t1 --alter="ADD KEY(name)"
-- Connecting to MySQL
-- Table sakila.t1 is of engine innodb
-- Checking for UNIQUE columns on sakila.t1, by which to chunk
-- Possible UNIQUE KEY column names in sakila.t1:
-- - id
-- Table sakila.__oak_t1 has been created
-- Table sakila.__oak_t1 has been altered
-- Checking for UNIQUE columns on sakila.__oak_t1, by which to chunk
-- Possible UNIQUE KEY column names in sakila.__oak_t1:
-- - id
-- Checking for UNIQUE columns on sakila.t1, by which to chunk
-- - Found following possible unique keys:
-- - id (int)
-- Chosen unique key is 'id'
-- Shared columns: id, name
-- Created AD trigger
-- Created AU trigger
-- Created AI trigger
-- Attempting to lock tables -- Tables locked WRITE
/usr/local/bin/oak-online-alter-table:: Warning: No data - zero rows fetched, selected, or processed
num_affected_rows = cursor.execute(query)
-- id (min, max) values: ([None], [None])
-- Tables unlocked
-- Table sakila.t1 has been renamed to sakila.__arc_t1,
-- and table sakila.__oak_t1 has been renamed to sakila.t1
-- Table sakila.__arc_t1 was found and dropped
-- ALTER TABLE completed
[root@xuanzhi-mysql ~]#
可以看到已经添加成功了,我们查看下表结构,是否真的成功了:(上面的输出有一个警告,不用理会,是因为我是空表,没有记录)
mysql> show create table t1\G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`id` int(11) DEFAULT NULL,
`name` char(20) DEFAULT NULL,
UNIQUE KEY `id` (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec) mysql>
在添加字段时如果设置了NOT NULL,但没有给默认值,也会报警告
[root@xuanzhi-mysql ~]# oak-online-alter-table -uroot -p123456 -S /data/mysql-5.5.40/mysql.sock --table=sakila.t1 --alter="ADD COLUMN sex VARCHAR(64) not null"
-- Connecting to MySQL
-- Table sakila.t1 is of engine innodb
-- Checking for UNIQUE columns on sakila.t1, by which to chunk
-- Possible UNIQUE KEY column names in sakila.t1:
-- - id
-- Table sakila.__oak_t1 has been created
-- Table sakila.__oak_t1 has been altered
-- Checking for UNIQUE columns on sakila.__oak_t1, by which to chunk
-- Possible UNIQUE KEY column names in sakila.__oak_t1:
-- - id
-- Checking for UNIQUE columns on sakila.t1, by which to chunk
-- - Found following possible unique keys:
-- - id (int)
-- Chosen unique key is 'id'
-- Shared columns: salarey, id, name
-- Created AD trigger
-- Created AU trigger
-- Created AI trigger
-- Attempting to lock tables -- Tables locked WRITE
-- id (min, max) values: ([1L], [1L])
-- Tables unlocked
-- - Reminder: altering sakila.t1: ADD COLUMN sex VARCHAR(64) not...
-- Copying range (1), (1), progress: 100%
/usr/local/bin/oak-online-alter-table:84: Warning: Field 'sex' doesn't have a default value
num_affected_rows = cursor.execute(query)
-- Copying range 100% complete. Number of rows: 1
-- - Reminder: altering sakila.t1: ADD COLUMN sex VARCHAR(64) not...
-- Deleting range (1), (1), progress: 100%
-- Deleting range 100% complete. Number of rows: 0
-- Table sakila.t1 has been renamed to sakila.__arc_t1,
-- and table sakila.__oak_t1 has been renamed to sakila.t1
-- Table sakila.__arc_t1 was found and dropped
-- ALTER TABLE completed
[root@xuanzhi-mysql ~]#
mysql> desc t1;
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id | int(11) | YES | UNI | NULL | |
| name | char(20) | YES | MUL | NULL | |
| sex | varchar(64) | NO | | NULL | |
+---------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec) mysql>
oak-online-alter-table还有更多的操作,同学们自己测试哈。
下面测试一下各种操作是否会锁表,这也是我们最关心的问题。
1、我们直接在mysql终端直接执行添加字段看看有什么情况:
mysql> show processlist;
+----+------+-----------+------------+---------+------+---------------------------------+------------------------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------+------------+---------+------+---------------------------------+------------------------------------------------------------+
| 25 | root | localhost | distribute | Query | 53 | copy to tmp table | alter table test1 add age int(3) |
| 26 | root | localhost | distribute | Query | 28 | Waiting for table metadata lock | insert into test1(name,code) values ('xuanhi','aa102') |
| 29 | root | localhost | distribute | Query | 0 | NULL | show processlist |
+----+------+-----------+------------+---------+------+---------------------------------+------------------------------------------------------------+
3 rows in set (0.00 sec)
相信大家都看到,在添加表字段的时候,会把整个表锁住,所以看到session2窗口插入数据时,要等待释放锁。
2、我们再测试上添加普通索引看看会不会锁表:
可以看到session2窗口也一样要等待的。如果对一个很大的表直接进行添加或者删除字段和索引的时候,会阻塞所有对该表的DML操作的,所以在线上谨慎直接添加或者删除字段和索引
我们用oak-online-alter-table
[root@xuanzhi-mysql ~]# oak-online-alter-table -uroot -p123456 -S /data/mysql-5.5./mysql.sock --table=distribute.test1 --alter="ADD COLUMN address VARCHAR(64)"
.....
......
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- - Reminder: altering distribute.test1: ADD COLUMN address VARCHAR()...
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range % complete. Number of rows:
-- Table distribute.test1 has been renamed to distribute.__arc_test1,
-- and table distribute.__oak_test1 has been renamed to distribute.test1
-- Table distribute.__arc_test1 was found and dropped
-- ALTER TABLE completed
在seesion2进行DML操作:
mysql> delete from test1 where name="xuanhi4";
Query OK, 1 row affected (2.69 sec) mysql> insert into test1(name,code) values ('xuanhi4','aa1333');
Query OK, 1 row affected (0.04 sec) mysql> select * from test1 where code='aa1333';
+---------+---------+--------+
| id | name | code |
+---------+---------+--------+
| 7014150 | xuanhi4 | aa1333 |
+---------+---------+--------+
1 row in set (1.12 sec) mysql> update test1 set name="xuanhi5" where id=7014150;
Query OK, 1 row affected (0.11 sec)
Rows matched: 1 Changed: 1 Warnings: 0 mysql>
可以看到执行成功的返回时间都是很少的,执行操作的时候并没有锁等待。
我们添加索引看看,是否要锁等待:
[root@xuanzhi-mysql ~]# oak-online-alter-table -uroot -p123456 -S /data/mysql-5.5./mysql.sock --table=distribute.test1 --alter="ADD KEY (name,age)"
...
....
......
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- - Reminder: altering distribute.test1: ADD KEY (name,age)...
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range (), (), progress: %
-- Deleting range % complete. Number of rows:
-- Table distribute.test1 has been renamed to distribute.__arc_test1,
-- and table distribute.__oak_test1 has been renamed to distribute.test1
-- Table distribute.__arc_test1 was found and dropped
-- ALTER TABLE completed
show processlist 查看是否有锁表:
mysql> show processlist;
+----+------+-----------+------------+---------+------+--------------+------------------------------------------------------------------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------+------------+---------+------+--------------+------------------------------------------------------------------------------------------------------+
| 25 | root | localhost | distribute | Sleep | 544 | | NULL |
| 26 | root | localhost | distribute | Query | 1 | NULL | show processlist |
| 29 | root | localhost | distribute | Sleep | 1260 | | NULL |
| 31 | root | localhost | distribute | Query | 1 | Sending data | INSERT IGNORE INTO distribute.__oak_test1 (`age`, `code`, `id`, `name`, `address`)
(SELE |
+----+------+-----------+------------+---------+------+--------------+------------------------------------------------------------------------------------------------------+
4 rows in set (0.45 sec) mysql>
可以看到使用工具在线添加索引和字段都不会锁表,有兴趣的朋友,可以测试删除字段和索引的,其实一样的,我这里就不测试了。mysql5.6虽然支持了Online DDL,但mysql 5.6 Online DDL的时候测试过如果在执行alter table之前已经有一个慢查询或者结果集比较大的查询,那么此时执行ALTER TABLE是会导致锁表的,用oak-online-alter-table也是一样的要等待锁的释放,本人已经测试过。(mysql5.6 online ddl的博客下次有空会补上)
mysql> show processlist;
+----+------+-----------+------------+---------+------+---------------------------------+------------------------------------------------------------------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------+------------+---------+------+---------------------------------+------------------------------------------------------------------------------------------------------+
| 25 | root | localhost | distribute | Query | 0 | NULL | show processlist |
| 26 | root | localhost | distribute | Sleep | 961 | | NULL |
| 29 | root | localhost | distribute | Query | 19 | Sending data | select * from test1 |
| 32 | root | localhost | distribute | Query | 6 | Waiting for table metadata lock | CREATE TRIGGER distribute.test1_AD_oak AFTER DELETE ON distribute.test1
FOR EACH ROW
|
+----+------+-----------+------------+---------+------+---------------------------------+------------------------------------------------------------------------------------------------------+
4 rows in set (0.25 sec) mysql>
oak-online-alter-table工具的使用,暂时说到这里,有兴趣的朋友可以参考官网
http://openarkkit.googlecode.com/svn/trunk/openarkkit/doc/html/oak-online-alter-table.html(自备梯子)
二、pt-online-schema-change
该工具是percona-toolkit工具包中其中的一个工具,简单说和oak-online-alter-table有着一样的功能。都是实现在线架构改变的工具。其他的我就不多说了。重点说工作原理和注意事项。
(1)安装依赖包:
[root@xuanzhi-mysql ~]# yum install perl-IO-Socket-SSL perl-DBD-MySQL perl-Time-HiRes -y
(2)下载软件:
[root@xuanzhi-mysql ~]# wget http://www.percona.com/downloads/percona-toolkit/LATEST/RPM/percona-toolkit-2.2.8-1.noarch.rpm
(3)安装软件
[root@xuanzhi-mysql ~]# rpm -ivh percona-toolkit-2.2.-.noarch.rpm
warning: percona-toolkit-2.2.-.noarch.rpm: Header V4 DSA/SHA1 Signature, key ID cd2efd2a: NOKEY
Preparing... ########################################### [%]
:percona-toolkit ########################################### [%]
[root@xuanzhi-mysql ~]#
大概工作原理如下:
(1)如果存在外键,根据alter-foreign-keys-method参数的值,检测外键相关的表,针对相应的设置进行处理。
(2)创建一个新的表,表结构为修改后的数据表,用于从源数据表向新表中导入数据。
(3)创建触发器,在复制数据开始之后,将对源数据表继续进行数据修改的操作记录下来,以便在数据复制结束后执行这些操作,保证数据不会丢失。
(4)复制数据,从源数据表中复制数据到新表中。
(5)修改外键相关的子表,根据修改后的数据,修改外键关联的子表。
(6)更改源数据表为old表,把新表改为源表名,并将old表删除。
(7)删除触发器。
存在如下限制:
(1)对操作的表必须要有主键或者唯一键
(2)增加的字段如果为NOT NULL,会报错,需要添加默认值才可以成功。
测试:
使用方法:
[root@xuanzhi-mysql ~]# pt-online-schema-change
Usage: pt-online-schema-change [OPTIONS] DSN
测试表test2结构如下:
mysql> show create table test2\G
*************************** 1. row ***************************
Table: test2
Create Table: CREATE TABLE `test2` (
`id` int(11) DEFAULT NULL,
`age` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec) mysql>
给表test2添加一个字段:
[root@xuanzhi-mysql ~]# pt-online-schema-change --alter="add column name char(20)" --user=root --password= --socket=/data/mysql-5.5./mysql.sock D=sakila,t=test2 --execute
No slaves found. See --recursion-method if host redis-master has slaves.
Not checking slave lag because no slaves were found and --check-slave-lag was not specified.
Operation, tries, wait:
copy_rows, , 0.25
create_triggers, ,
drop_triggers, ,
swap_tables, ,
update_foreign_keys, ,
Altering `sakila`.`test2`...
Creating new table...
Created new table sakila._test2_new OK.
Altering new table...
Altered `sakila`.`_test2_new` OK.
--27T22:: Dropping new table...
--27T22:: Dropped new table OK.
`sakila`.`test2` was not altered.
The new table `sakila`.`_test2_new` does not have a PRIMARY KEY or a unique index which is required for the DELETE trigger.
[root@xuanzhi-mysql ~]#
可以发现提示表没有主键或者唯一键,所以添加失败。添加主键以后再进行测试。
mysql> alter table test2 add primary key (id);
Query OK, rows affected (0.04 sec)
Records: Duplicates: Warnings: mysql>
[root@xuanzhi-mysql ~]# pt-online-schema-change --alter="add column name char(20)" --user=root --password= --socket=/data/mysql-5.5./mysql.sock D=sakila,t=test2 --execute
No slaves found. See --recursion-method if host redis-master has slaves.
Not checking slave lag because no slaves were found and --check-slave-lag was not specified.
Operation, tries, wait:
copy_rows, , 0.25
create_triggers, ,
drop_triggers, ,
swap_tables, ,
update_foreign_keys, ,
Altering `sakila`.`test2`...
Creating new table...
Created new table sakila._test2_new OK.
Altering new table...
Altered `sakila`.`_test2_new` OK.
--27T22:: Creating triggers...
--27T22:: Created triggers OK.
--27T22:: Copying approximately rows...
--27T22:: Copied rows OK.
--27T22:: Swapping tables...
--27T22:: Swapped original and new tables OK.
--27T22:: Dropping old table...
--27T22:: Dropped old table `sakila`.`_test2_old` OK.
--27T22:: Dropping triggers...
--27T22:: Dropped triggers OK.
Successfully altered `sakila`.`test2`.
[root@xuanzhi-mysql ~]#
可以看到添加了主键后,就成功添加了。但是设置NOT NULL,但是不给默认值,看看神马情况
[root@xuanzhi-mysql ~]# pt-online-schema-change --alter="add column last_name char(20) not null" --user=root --password= --socket=/data/mysql-5.5./mysql.sock D=sakila,t=test2 --execute
No slaves found. See --recursion-method if host redis-master has slaves.
Not checking slave lag because no slaves were found and --check-slave-lag was not specified.
Operation, tries, wait:
copy_rows, , 0.25
create_triggers, ,
drop_triggers, ,
swap_tables, ,
update_foreign_keys, ,
Altering `sakila`.`test2`...
Creating new table...
Created new table sakila._test2_new OK.
Altering new table...
Altered `sakila`.`_test2_new` OK.
--27T23:: Creating triggers...
--27T23:: Created triggers OK.
--27T23:: Copying approximately rows...
--27T23:: Dropping triggers...
--27T23:: Dropped triggers OK.
--27T23:: Dropping new table...
--27T23:: Dropped new table OK.
`sakila`.`test2` was not altered.
--27T23:: Error copying rows from `sakila`.`test2` to `sakila`.`_test2_new`: --27T23:: Copying rows caused a MySQL error :
Level: Warning
Code:
Message: Field 'last_name' doesn't have a default value
Query: INSERT LOW_PRIORITY IGNORE INTO `sakila`.`_test2_new` (`id`, `age`, `name`) SELECT `id`, `age`, `name` FROM `sakila`.`test2` LOCK IN SHARE MODE /*pt-online-schema-change 4369 copy table*/ [root@xuanzhi-mysql ~]#
可以看到没有给默认值的情况下,添加字段失败,下面给一个默认值再看看:
[root@xuanzhi-mysql ~]# pt-online-schema-change --alter="add column last_name char(20) not null default 'xuanzhi'" --user=root --password= --socket=/data/mysql-5.5./mysql.sock D=sakila,t=test2 --execute
No slaves found. See --recursion-method if host redis-master has slaves.
Not checking slave lag because no slaves were found and --check-slave-lag was not specified.
Operation, tries, wait:
copy_rows, , 0.25
create_triggers, ,
drop_triggers, ,
swap_tables, ,
update_foreign_keys, ,
Altering `sakila`.`test2`...
Creating new table...
Created new table sakila._test2_new OK.
Altering new table...
Altered `sakila`.`_test2_new` OK.
--27T23:: Creating triggers...
--27T23:: Created triggers OK.
--27T23:: Copying approximately rows...
--27T23:: Copied rows OK.
--27T23:: Swapping tables...
--27T23:: Swapped original and new tables OK.
--27T23:: Dropping old table...
--27T23:: Dropped old table `sakila`.`_test2_old` OK.
--27T23:: Dropping triggers...
--27T23:: Dropped triggers OK.
Successfully altered `sakila`.`test2`.
[root@xuanzhi-mysql ~]#
可以看见已经成功了,相信更多的小伙伴想看看对大表添加字段和索引会不会锁表,莫急,下面我们一起来道道:
下面对一个有六百多万行数据的测试表进行添加字段看是否会锁表:(如果想自己造数据的同学可以用sysbench生成的1000w数据)
mysql> show create table xuanzhi\G
*************************** 1. row ***************************
Table: xuanzhi
Create Table: CREATE TABLE `xuanzhi` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`code` varchar(32) DEFAULT NULL,
`age` int(3) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `code_index` (`code`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=7014157 DEFAULT CHARSET=utf8
1 row in set (0.00 sec) mysql> select count(*) from xuanzhi;
+----------+
| count(*) |
+----------+
| 6862437 |
+----------+
1 row in set (0.03 sec) mysql>
测试1、在线添加字段并查看是否有阻塞DML操作
[root@xuanzhi-mysql ~]# pt-online-schema-change --alter="add column name char(20) not null default 'man'" --user=root --password=123456 --socket=/data/mysl-5.5.40/mysql.sock D=sakila,t=xuanzhi --execute
Operation, tries, wait:
copy_rows, 10, 0.25
create_triggers, 10, 1
drop_triggers, 10, 1
swap_tables, 10, 1
update_foreign_keys, 10, 1
Altering `sakila`.`xuanzhi`...
Creating new table...
Created new table sakila._xuanzhi_new OK.
Altering new table...
Altered `sakila`.`_xuanzhi_new` OK.
2015-05-28T01:38:44 Creating triggers...
2015-05-28T01:38:44 Created triggers OK.
2015-05-28T01:38:44 Copying approximately 6862437 rows...
Copying `sakila`.`xuanzhi`: 29% 01:13 remain
Copying `sakila`.`xuanzhi`: 51% 00:55 remain
Copying `sakila`.`xuanzhi`: 66% 00:45 remain
Copying `sakila`.`xuanzhi`: 73% 00:43 remain
Copying `sakila`.`xuanzhi`: 78% 00:40 remain
Copying `sakila`.`xuanzhi`: 85% 00:31 remain
Copying `sakila`.`xuanzhi`: 91% 00:20 remain
Copying `sakila`.`xuanzhi`: 95% 00:10 remain
2015-05-28T01:43:07 Copied rows OK.
2015-05-28T01:43:07 Swapping tables...
2015-05-28T01:43:21 Swapped original and new tables OK.
2015-05-28T01:43:21 Dropping old table...
2015-05-28T01:43:21 Dropped old table `sakila`.`_xuanzhi_old` OK.
2015-05-28T01:43:21 Dropping triggers...
2015-05-28T01:43:21 Dropped triggers OK.
Successfully altered `sakila`.`xuanzhi`.
[root@xuanzhi-mysql ~]#
可以看到并没有阻塞DML操作,上面执行成功的返回时间有点久,可以忽略,因为在虚拟机测试生成的报告,所以同学们懂的!!
测试2:在线添加索引,看是否阻塞DML操作
[root@xuanzhi-mysql ~]# pt-online-schema-change --alter="ADD KEY (name)" --user=root --password= --socket=/data/mysql-5.5./mysql.sock D=sakila,t=xuanzhi --execute
No slaves found. See --recursion-method if host redis-master has slaves.
Not checking slave lag because no slaves were found and --check-slave-lag was not specified.
Operation, tries, wait:
copy_rows, , 0.25
create_triggers, ,
drop_triggers, ,
swap_tables, ,
update_foreign_keys, ,
Altering `sakila`.`xuanzhi`...
Creating new table...
Created new table sakila._xuanzhi_new OK.
Altering new table...
Altered `sakila`.`_xuanzhi_new` OK.
--28T01:: Creating triggers...
--28T01:: Created triggers OK.
--28T01:: Copying approximately rows...
Copying `sakila`.`xuanzhi`: % : remain
Copying `sakila`.`xuanzhi`: % : remain
Copying `sakila`.`xuanzhi`: % : remain
Copying `sakila`.`xuanzhi`: % : remain
Copying `sakila`.`xuanzhi`: % : remain
Copying `sakila`.`xuanzhi`: % : remain
Copying `sakila`.`xuanzhi`: % : remain
Copying `sakila`.`xuanzhi`: % : remain
Copying `sakila`.`xuanzhi`: % : remain
Copying `sakila`.`xuanzhi`: % : remain
Copying `sakila`.`xuanzhi`: % : remain
Copying `sakila`.`xuanzhi`: % : remain
--28T02:: Copied rows OK.
--28T02:: Swapping tables...
--28T02:: Swapped original and new tables OK.
--28T02:: Dropping old table...
--28T02:: Dropped old table `sakila`.`_xuanzhi_old` OK.
--28T02:: Dropping triggers...
--28T02:: Dropped triggers OK.
Successfully altered `sakila`.`xuanzhi`.
[root@xuanzhi-mysql ~]#
相信大家都看到了吧,在线添加索引,对DML操作是木有阻塞的。最后查看一下表结构:
mysql> show create table xuanzhi\G
*************************** 1. row ***************************
Table: xuanzhi
Create Table: CREATE TABLE `xuanzhi` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`code` varchar(32) DEFAULT NULL,
`age` int(3) DEFAULT NULL,
`name` char(20) NOT NULL DEFAULT 'man',
PRIMARY KEY (`id`),
UNIQUE KEY `code_index` (`code`) USING BTREE,
KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=7014161 DEFAULT CHARSET=utf8
1 row in set (0.08 sec) mysql>
成功添加了name字段,成功的在列name上添加了普通索引。
测试3:测试一下在执行alter table之前有一个大的查询,看是否导致锁等待,这个在MySQL 5.6以及oak-online-alter-table都有这个问题
在session1窗口:
mysql> select * from xuanzhi;
在session2和session3窗口查看:
并没有发现锁表的情况,但在网上看到的资料是会锁表的,希望同学们也自己测试下,大家一起学习哈!!
总结:
一、如果要在线上进行Online DDL操作,一定要做好数据备份,要考虑数据的大小情况及主从框架中如果从是提供读的,要考虑到延时等问题。
二、pt-online-schema-change比oak-online-alter-table工具更好用,并且存在的限制较少,oak-online-alter-table对有外键的表是没有办法的
三、已经执行了大的查询,这时恰好执行ALTER TABLE操作,都会导致锁表,MySQL5.6版本也有这样的情况。
四、MySQL5.6版本已经支持Online DDL了,这是一个不错的改进。如果对一个大数据表DDL,一般选择避开业务高峰期执行,所以还是要在业务量较低且没有大查询时执行Online DDL
参考资料:
https://openarkkit.googlecode.com/svn/trunk/openarkkit/doc/html/oak-online-alter-table.html(自备梯子)
https://www.percona.com/doc/percona-toolkit/2.1/pt-online-schema-change.html
http://www.cnblogs.com/gomysql/p/3777607.html
作者:陆炫志 出处:xuanzhi的博客 http://www.cnblogs.com/xuanzhi201111 您的支持是对博主最大的鼓励,感谢您的认真阅读。本文版权归作者所有,欢迎转载,但请保留该声明。 |
Online DDL工具的安装与使用的更多相关文章
- MySQL在线DDL工具 gh-ost
一.简介 gh-ost基于 golang 语言,是 github 开源的一个 DDL 工具,是 GitHub's Online Schema Transmogrifier/Transfigurator ...
- 微软源代码管理工具TFS2013安装与使用详细图文教程(Vs2013)
这篇文章联合软件小编主要介绍了微软源代码管理工具TFS2013安装与使用图文教程,本文详细的给出了TFS2013的安装配置过程.使用教程,需要的朋友可以参考下 最近公司新开发一个项目要用微软的TFS2 ...
- [转] 微软源代码管理工具TFS2013安装与使用详细图文教程(Vs2013)
这篇文章联合软件小编主要介绍了微软源代码管理工具TFS2013安装与使用图文教程,本文详细的给出了TFS2013的安装配置过程.使用教程,需要的朋友可以参考下 最近公司新开发一个项目要用微软的TFS2 ...
- nmon工具的安装及简单使用
1.工具的安装 下载rpm包安装即可http://mirror.ghettoforge.org/distributions/gf/el/6/gf/x86_64/nmon-14i-1.gf.el6.x8 ...
- PHP性能优化工具–xhprof安装
PHP性能优化工具–xhprof安装,这里我先贴出大致的步骤: 1.获取xhprof 2.编译前预处理 3.编译安装 4.配置php.ini 5.查看运行结果 那么下面我们开始安装xhprof工具吧: ...
- [资料收集]MySQL在线DDL工具pt-online-schema-change
MySQL在线DDL工具pt-online-schema-change pt-online-schema-change使用说明(未完待续) 官网
- PHP 代码质量检测工具的安装与使用
代码统计工具 PHPLOC安装:wget https://phar.phpunit.de/phploc.phar chmod +x phploc.phar sudo mv phploc.phar /u ...
- Hadoop集群中pig工具的安装过程记录
在Hadoop环境中安装了pig工具,安装过程中碰到了一些问题,在此做一下记录: 主要安装流程参考:http://www.cnblogs.com/yanghuahui/p/3768270.html ...
- 第一章:绪论-Python开发工具的安装
书中提到了操作系统平台尽量选 *nix.我这里选用的是 ubuntu 14.04 , 下面的操作均以此操作系统为例说明. 操作系统安装教程可以去网站上找,推荐用虚拟机的方式,Windows下可用的虚拟 ...
随机推荐
- 使用 TListView 控件(4)
本例效果图: 代码文件: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, ...
- 【Mysql】根据时间去除重复数据
SELECT a.project_id,a.user_id,a.app_version,a.src_system,a.channel,a.thedate FROM rpt_innoreport_luc ...
- Nastya and a Wardrobe CodeForces - 992C(规律)
写一下二叉树 推一下公式就出来了, 注意取模时的输出形式 #include <bits/stdc++.h> #define mem(a, b) memset(a, b, sizeof(a ...
- 解决 Previous operation has not finihsed; run ‘cleanup’ if it was interrupted Please execute the ‘Cleanup’ command
更新时遇到这个问题,解决方法如下: 把根目录下的.svn目录删除掉,再checkout,然后就会出现下面的加version的action. 疯吻IT
- 【bzoj2961】 共点圆
http://www.lydsy.com/JudgeOnline/problem.php?id=2961 (题目链接) 题意 按照一定的顺序给出一些圆和一些点,对于每一个点问是否在所有圆内. Solu ...
- 【POJ3171】Cleaning Shifts 带权区间最小覆盖
题目大意:给定一个长度为 N 的序列,求带权区间最小覆盖. 题解:设 \(dp[i]\) 表示从左端点到 i 的最小权值是多少,则状态转移为:\(dp[e[i].ed]=min\{dp[j],j\in ...
- C++ new动态数组初始化
strlen函数是不包括‘\0’的长度的,sizeof计算的结果才包括'\0'的长度: C++ new动态数组初始化void testnew( const char* str ) { if (!str ...
- spring boot 配置数据源
以postgreSQL为例,方便下次直接使用. 其中pom.xml引入如下依赖. <?xml version="1.0" encoding="UTF-8" ...
- bzoj千题计划218:bzoj2333: [SCOI2011]棘手的操作
http://www.lydsy.com/JudgeOnline/problem.php?id=2333 上次那个是线段树,再发一个左偏树 维护两种左偏树 第一种是对每个联通块维护一个左偏树 第二种是 ...
- bzoj千题计划198:bzoj1084: [SCOI2005]最大子矩阵
http://www.lydsy.com/JudgeOnline/problem.php?id=1084 m=1: dp[i][j] 前i个数,选了j个矩阵的最大和 第i个不选:由dp[i-1][j] ...