前言

在上篇文章中提到了MySQL 5.6 Online DDL,如果是MySQL 5.5的版本在DDL方面是要付出代价的,虽然已经有了Fast index Creation,但是在添加字段还是会锁表的,而且在添加删除辅助索引是会加S锁,也就是无法进行写操作。所以,这里就有相关工具的出现,那就是pt-online-schema-change和oak-online-alter-table,都实现了Online DDL,但是每个工具都有相应自己的限制,下面让我慢慢道来。

一.oak-online-alter-table

openark工具包是一组用于MySQL的实用工具,该工具集解决日常维护任务,这些工作比较复杂和耗时。其中oak-online-alter-table就是该工具集中的一个工具,该工具执行非阻塞ALTER TABLE的操作。当然还有其他的工具,童鞋们自行查阅资料。

(1)安装openark工具包(安装依赖)

[root@yayun-mysql-server ~]# yum install python-mysqldb MySQL-python -y

(2)软件下载

[root@yayun-mysql-server ~]# wget https://openarkkit.googlecode.com/files/openark-kit-196-1.noarch.rpm

(3)安装

[root@yayun-mysql-server ~]# rpm -ivh openark-kit--.noarch.rpm
Preparing... ########################################### [%]
:openark-kit ########################################### [%]
[root@yayun-mysql-server ~]#

在使用oak-online-alter-table对表执行ALTER TABLE时存在如下限制:

在该表上面至少有一个单列的UNIQUE KEY
更改原始表为单个字段的唯一索引
该表没有定义触发器"AFTER"(oak会自己创建触发器)
该表没有FOREIGN KEY
表名长度不超过57个字符

改工具提供了以下三种基本功能

1.一个非阻塞ALTER TABLE操作:添加列或索引,删除列或索引,修改列,表字符集转换等,都是支持的,如下:
添加列(新列必须有一个默认值)
删除列(旧表必须有一个单列的唯一索引)
修改列(改变字段类型,包括唯一键的列)
添加索引(普通索引,唯一索引,全文索引。)
删除索引(旧表必须有一个单列的唯一索引)
修改表引擎:有效,但应格外注意当处理事务性引擎
添加外键约束

2.一个空的ALTER,重建一个表:释放磁盘空间和重新组织表,相当于优化表。

3.(可能会在未来版本不再支持):创建一个镜像表,与原始表同步,只要不发生如下操作:
对原始表ALTER TABLE
对原始表TRUNCATE
使用LOAD DATA INFILE向原始表导入数据
对原始表OPTIMIZE 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)。在操作完成时才出现磁盘空间恢复(取决于你的存储引擎和配置)。

测试如下:

首先添加一个字段看看

[root@yayun-mysql-server ~]# oak-online-alter-table -S /tmp/mysqld.sock -u root -p 123456 --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@yayun-mysql-server ~]#

很明显提示有触发器,也是上面提到的限制。

[root@yayun-mysql-server ~]# oak-online-alter-table -S /tmp/mysqld.sock -u root -p 123456 --table=employees.titles --alter="ADD COLUMN name VARCHAR(64) DEFAULT ''",
-- Connecting to MySQL
-- Table employees.titles 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).
[root@yayun-mysql-server ~]#

很明显提示有外键,也是上面提到的限制

(root@localhost 16:50:53)[dyy]> 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) (root@localhost 16:51:00)[dyy]>

下面给t1表添加一个辅助索引看看

[root@yayun-mysql-server ~]# oak-online-alter-table -S /tmp/mysqld.sock -u root -p 123456 --table=dyy.t1 --alter="ADD KEY(name)"
-- Connecting to MySQL
-- Table dyy.t1 is of engine innodb
-- Checking for UNIQUE columns on dyy.t1, by which to chunk
-- Possible UNIQUE KEY column names in dyy.t1:
-- ERROR: Errors found. Initiating cleanup
-- Tables unlocked
-- ERROR: Table must have a UNIQUE KEY on a single column
[root@yayun-mysql-server ~]#

提示没有唯一键,这也是上面提到的限制,添加一个唯一键然后我们再尝试添加索引

(root@localhost 16:53:37)[dyy]> alter table t1 add unique key (id);
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0 (root@localhost 16:53:41)[dyy]>
[root@yayun-mysql-server ~]# oak-online-alter-table -S /tmp/mysqld.sock -u root -p 123456 --table=dyy.t1 --alter="ADD KEY(name)"
-- Connecting to MySQL
-- Table dyy.t1 is of engine innodb
-- Checking for UNIQUE columns on dyy.t1, by which to chunk
-- Possible UNIQUE KEY column names in dyy.t1:
-- - id
-- Table dyy.__oak_t1 has been created
-- Table dyy.__oak_t1 has been altered
-- Checking for UNIQUE columns on dyy.__oak_t1, by which to chunk
-- Possible UNIQUE KEY column names in dyy.__oak_t1:
-- - id
-- Checking for UNIQUE columns on dyy.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:84: Warning: No data - zero rows fetched, selected, or processed
num_affected_rows = cursor.execute(query)
-- id (min, max) values: ([None], [None])
-- Tables unlocked
-- Table dyy.t1 has been renamed to dyy.__arc_t1,
-- and table dyy.__oak_t1 has been renamed to dyy.t1
-- Table dyy.__arc_t1 was found and dropped
-- ALTER TABLE completed
[root@yayun-mysql-server ~]#

可以看见添加成功,我们看看表结构,是否真的成功了。上面的输出有一个警告,不用理会,是因为我是空表,没有记录。

(root@localhost 16:56:50)[dyy]> 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) (root@localhost 16:57:10)[dyy]>

在添加字段时如果设置了NOT NULL,但没有给默认值,也会报警告,但是不人性化(起码不应该抛代码在什么行嘛,直接最后给一个Warning多好)

[root@yayun-mysql-server ~]# oak-online-alter-table -S /tmp/mysqld.sock -u root -p 123456 --table=dyy.t1 --alter="ADD COLUMN salarey VARCHAR(64) not null"
-- Connecting to MySQL
-- Table dyy.t1 is of engine innodb
-- Checking for UNIQUE columns on dyy.t1, by which to chunk
-- Possible UNIQUE KEY column names in dyy.t1:
-- - id
-- Table dyy.__oak_t1 has been created
-- Table dyy.__oak_t1 has been altered
-- Checking for UNIQUE columns on dyy.__oak_t1, by which to chunk
-- Possible UNIQUE KEY column names in dyy.__oak_t1:
-- - id
-- Checking for UNIQUE columns on dyy.t1, by which to chunk
-- - Found following possible unique keys:
-- - id (int)
-- Chosen unique key is 'id'
-- Shared columns: id, name, address
-- 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 dyy.t1: ADD COLUMN salarey VARCHAR(64)...
-- Copying range (1), (1), progress: 100%
/usr/local/bin/oak-online-alter-table:84: Warning: Field 'salarey' doesn't have a default value
num_affected_rows = cursor.execute(query)
-- Copying range 100% complete. Number of rows: 1
-- - Reminder: altering dyy.t1: ADD COLUMN salarey VARCHAR(64)...
-- Deleting range (1), (1), progress: 100%
-- Deleting range 100% complete. Number of rows: 0
-- Table dyy.t1 has been renamed to dyy.__arc_t1,
-- and table dyy.__oak_t1 has been renamed to dyy.t1
-- Table dyy.__arc_t1 was found and dropped
-- ALTER TABLE completed

查看表结构,还是添加成功了的。

(root@localhost 17:08:22)[(none)]> desc dyy.t1;
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id | int(11) | YES | UNI | NULL | |
| name | char(20) | YES | MUL | NULL | |
| address | varchar(64) | YES | | NULL | |
| salarey | varchar(64) | NO | | NULL | |
+---------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

好了,更多的测试同学们自行测试哈,下面测试一下各种操作是否会锁表,这也是我们最关心的问题。测试的表是使用sysbench生成的1000w数据,具体的命令请阅读前面的文章MySQL 5.6 Online DDL

(root@localhost 17:22:55)[sbtest]> select count(*) from sbtest;
+----------+
| count(*) |
+----------+
| 10000000 |
+----------+
1 row in set (0.00 sec) (root@localhost 17:22:57)[sbtest]> show create table sbtest\G
*************************** 1. row ***************************
Table: sbtest
Create Table: CREATE TABLE `sbtest` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`k` int(10) unsigned NOT NULL DEFAULT '',
`c` char(120) NOT NULL DEFAULT '',
`pad` char(60) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=10000001 DEFAULT CHARSET=utf8
1 row in set (0.00 sec) (root@localhost 17:23:13)[sbtest]>

(1)首先添加一个字段看看session1执行alter table操作,session 2执行DML操作

session 1

[root@yayun-mysql-server ~]# oak-online-alter-table -S /tmp/mysqld.sock -u root -p  --table=sbtest.sbtest --alter="ADD COLUMN address VARCHAR(64)"
-- Connecting to MySQL
-- Table sbtest.sbtest is of engine innodb
-- Checking for UNIQUE columns on sbtest.sbtest, by which to chunk
-- Possible UNIQUE KEY column names in sbtest.sbtest:
-- - id
-- Table sbtest.__oak_sbtest has been created
-- Table sbtest.__oak_sbtest has been altered
-- Checking for UNIQUE columns on sbtest.__oak_sbtest, by which to chunk
-- Possible UNIQUE KEY column names in sbtest.__oak_sbtest:
-- - id
-- Checking for UNIQUE columns on sbtest.sbtest, by which to chunk
-- - Found following possible unique keys:
-- - id (int)
-- Chosen unique key is 'id'
-- Shared columns: c, pad, k, id
-- Created AD trigger
-- Created AU trigger
-- Created AI trigger
-- Attempting to lock tables -- Tables locked WRITE
-- id (min, max) values: ([1L], [10000000L])
-- Tables unlocked
-- - Reminder: altering sbtest.sbtest: ADD COLUMN address VARCHAR()...
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %

session 2

(root@localhost 17:25:52)[sbtest]> select * from sbtest where id=100;
+-----+---+---+----------------------------------------------------+
| id | k | c | pad |
+-----+---+---+----------------------------------------------------+
| 100 | 0 | | qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt |
+-----+---+---+----------------------------------------------------+
1 row in set (0.00 sec) (root@localhost 17:26:03)[sbtest]> delete from sbtest where id=100;
Query OK, 1 row affected (0.17 sec) (root@localhost 17:26:24)[sbtest]> insert into sbtest select 100,0,null,'cccc';
Query OK, 1 row affected, 1 warning (0.07 sec)
Records: 1 Duplicates: 0 Warnings: 1 (root@localhost 17:26:54)[sbtest]> update sbtest set k=101 where id=1111;
Query OK, 1 row affected (0.48 sec)
Rows matched: 1 Changed: 1 Warnings: 0 (root@localhost 17:27:40)[sbtest]> show processlist;
+----+------+-----------+--------+---------+------+-------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------+--------+---------+------+-------+------------------+
| 53 | root | localhost | sbtest | Query | 1 | NULL | show processlist |
| 54 | root | localhost | sbtest | Query | 0 | NULL | commit |
+----+------+-----------+--------+---------+------+-------+------------------+
2 rows in set (0.08 sec) (root@localhost 17:27:45)[sbtest]>

可以发现session 1的添加字段的操作并不影响session 2的操作。
(2)添加一个辅助索引看看神马情况

session 1

[root@yayun-mysql-server ~]# oak-online-alter-table -S /tmp/mysqld.sock -u root -p  --table=sbtest.sbtest --alter="ADD KEY(pad)"
-- Connecting to MySQL
-- Table sbtest.sbtest is of engine innodb
-- Dropped custom trigger sbtest_AD_oak
-- Dropped custom trigger sbtest_AU_oak
-- Dropped custom trigger sbtest_AI_oak
-- Checking for UNIQUE columns on sbtest.sbtest, by which to chunk
-- Possible UNIQUE KEY column names in sbtest.sbtest:
-- - id
-- Table sbtest.__oak_sbtest was found and dropped
-- Table sbtest.__oak_sbtest has been created
-- Table sbtest.__oak_sbtest has been altered
-- Checking for UNIQUE columns on sbtest.__oak_sbtest, by which to chunk
-- Possible UNIQUE KEY column names in sbtest.__oak_sbtest:
-- - id
-- Checking for UNIQUE columns on sbtest.sbtest, by which to chunk
-- - Found following possible unique keys:
-- - id (int)
-- Chosen unique key is 'id'
-- Shared columns: c, pad, k, id
-- Created AD trigger
-- Created AU trigger
-- Created AI trigger
-- Attempting to lock tables -- Tables locked WRITE
-- id (min, max) values: ([1L], [10000000L])
-- Tables unlocked
-- - Reminder: altering sbtest.sbtest: ADD KEY(pad)...
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %
-- Copying range (), (), progress: %

session 2

(root@localhost 17:32:23)[sbtest]> delete from sbtest where id=103;
Query OK, 1 row affected (0.09 sec) (root@localhost 17:32:32)[sbtest]> update sbtest set k=101 where id=103;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0 Changed: 0 Warnings: 0 (root@localhost 17:32:39)[sbtest]> select * from sbtest where id=2000;
+------+---+---+----------------------------------------------------+
| id | k | c | pad |
+------+---+---+----------------------------------------------------+
| 2000 | 0 | | qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt |
+------+---+---+----------------------------------------------------+
1 row in set (0.03 sec) (root@localhost 17:32:50)[sbtest]> show processlist;
+----+------+-----------+--------+---------+------+-------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------+--------+---------+------+-------+------------------+
| 53 | root | localhost | sbtest | Query | 0 | NULL | show processlist |
| 55 | root | localhost | sbtest | Query | 0 | NULL | commit |
+----+------+-----------+--------+---------+------+-------+------------------+
2 rows in set (0.03 sec) (root@localhost 17:32:58)[sbtest]>

依然读写不受影响。所以总体来说还是很好使用,只是有上面提到的那些限制需要注意一下。

我在说mysql 5.6 Online DDL的时候测试过如果在执行alter table之前已经有一个慢查询或者结果集比较大的查询,那么此时执行ALTER TABLE是会导致锁表的,那么我们测试一下oak-online-alter-table是否会一样。

session 1(sbtest表有1000w记录)

(root@localhost 17:41:07)[sbtest]> select * from sbtest;

session 2

[root@yayun-mysql-server ~]# oak-online-alter-table -S /tmp/mysqld.sock -u root -p  --table=sbtest.sbtest --alter="ADD KEY(pad)"

session 3

(root@localhost 17:37:54)[(none)]> show processlist;
+----+------+-----------+--------+---------+------+---------------------------------+---------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------+--------+---------+------+---------------------------------+---------------------------------------------+
| 53 | root | localhost | sbtest | Query | 9 | Sending data | select * from sbtest |
| 56 | root | localhost | NULL | Query | 0 | NULL | show processlist |
| 57 | root | localhost | sbtest | Query | 5 | Waiting for table metadata lock | DROP TRIGGER IF EXISTS sbtest.sbtest_AD_oak |
+----+------+-----------+--------+---------+------+---------------------------------+---------------------------------------------+
3 rows in set (0.05 sec) (root@localhost 17:38:10)[(none)]>

可以看见该工具的删除触发器操作在等待锁。好了,这里的情况和我在说MySQL 5.6 Online DDL的情况一样,大家自行查阅资料。好了,oak-online-alter-table就说这么多了。

二.pt-online-schema-change

改工具是percona-toolkit工具包中其中的一个工具,简单说和oak-online-alter-table有着一样的功能。都是实现在线架构改变的工具。其他的我就不多说了。重点说工作原理,注意事项。

(1)安装依赖包

[root@yayun-mysql-server ~]# yum install perl-IO-Socket-SSL perl-DBD-MySQL perl-Time-HiRes -y

(2)下载软件

[root@yayun-mysql-server ~]# wget http://www.percona.com/downloads/percona-toolkit/LATEST/RPM/percona-toolkit-2.2.8-1.noarch.rpm

(3)安装软件

[root@yayun-mysql-server ~]# 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@yayun-mysql-server ~]#

大概工作原理:

(1)如果存在外键,根据alter-foreign-keys-method参数的值,检测外键相关的表,针对相应的设置进行处理。

(2)创建一个新的表,表结构为修改后的数据表,用于从源数据表向新表中导入数据。

(3)创建触发器,在复制数据开始之后,将对源数据表继续进行数据修改的操作记录下来,以便在数据复制结束后执行这些操作,保证数据不会丢失。

(4)复制数据,从源数据表中复制数据到新表中。

(5)修改外键相关的子表,根据修改后的数据,修改外键关联的子表。

(6)更改源数据表为old表,把新表改为源表名,并将old表删除。

(7)删除触发器。

存在如下限制:

(1)对操作的表必须要有主键或者唯一键

(2)增加的字段如果为NOT NULL,会报错,需要添加默认值才可以成功。

实际测试:

用法

pt-online-schema-change [OPTIONS] DSN

测试表结构如下

root@localhost : dyy 23:38:47> show create table t1\G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`id` int(11) DEFAULT NULL,
`age` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec) root@localhost : dyy 23:39:01>

给表t1添加一个字段

[root@yayun-mysql-server ~]# pt-online-schema-change --alter="add column name char(20)" --user=root D=dyy,t=t1 --execute

# A software update is available:
# * The current version for Percona::Toolkit is 2.2.. Operation, tries, wait:
copy_rows, , 0.25
create_triggers, ,
drop_triggers, ,
swap_tables, ,
update_foreign_keys, ,
Altering `dyy`.`t1`...
Creating new table...
Created new table dyy._t1_new OK.
Altering new table...
Altered `dyy`.`_t1_new` OK.
--09T23:: Dropping new table...
--09T23:: Dropped new table OK.
`dyy`.`t1` was not altered.
The new table `dyy`.`_t1_new` does not have a PRIMARY KEY or a unique index which is required for the DELETE trigger.
[root@yayun-mysql-server ~]#

可以发现提示表没有主键或者唯一键,所以添加失败。添加主键以后再进行测试。

[root@yayun-mysql-server ~]# pt-online-schema-change --alter="add column name char(20)" --user=root D=dyy,t=t1 --execute
Operation, tries, wait:
copy_rows, , 0.25
create_triggers, ,
drop_triggers, ,
swap_tables, ,
update_foreign_keys, ,
Altering `dyy`.`t1`...
Creating new table...
Created new table dyy._t1_new OK.
Altering new table...
Altered `dyy`.`_t1_new` OK.
--09T23:: Creating triggers...
--09T23:: Created triggers OK.
--09T23:: Copying approximately rows...
--09T23:: Copied rows OK.
--09T23:: Swapping tables...
--09T23:: Swapped original and new tables OK.
--09T23:: Dropping old table...
--09T23:: Dropped old table `dyy`.`_t1_old` OK.
--09T23:: Dropping triggers...
--09T23:: Dropped triggers OK.
Successfully altered `dyy`.`t1`.
[root@yayun-mysql-server ~]#

可以看见已经成功咯,下面给表添加一个字段,但是设置NOT NULL,但是不给默认值,看看神马情况

[root@yayun-mysql-server ~]# pt-online-schema-change --alter="add column last_name char(20) not null" --user=root D=dyy,t=t1 --execute
Operation, tries, wait:
copy_rows, , 0.25
create_triggers, ,
drop_triggers, ,
swap_tables, ,
update_foreign_keys, ,
Altering `dyy`.`t1`...
Creating new table...
Created new table dyy._t1_new OK.
Altering new table...
Altered `dyy`.`_t1_new` OK.
--09T23:: Creating triggers...
--09T23:: Created triggers OK.
--09T23:: Copying approximately rows...
--09T23:: Dropping triggers...
--09T23:: Dropped triggers OK.
--09T23:: Dropping new table...
--09T23:: Dropped new table OK.
`dyy`.`t1` was not altered.
--09T23:: Error copying rows from `dyy`.`t1` to `dyy`.`_t1_new`: --09T23:: 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 `dyy`.`_t1_new` (`id`, `age`, `name`) SELECT `id`, `age`, `name` FROM `dyy`.`t1` LOCK IN SHARE MODE /*pt-online-schema-change 3479 copy table*/ [root@yayun-mysql-server ~]#

可以看见我没有给默认值,添加字段失败,下面给一个默认值,再瞧瞧

[root@yayun-mysql-server ~]# pt-online-schema-change --alter="add column last_name char(20) not null default 'yayun'" --user=root D=dyy,t=t1 --execute
Operation, tries, wait:
copy_rows, , 0.25
create_triggers, ,
drop_triggers, ,
swap_tables, ,
update_foreign_keys, ,
Altering `dyy`.`t1`...
Creating new table...
Created new table dyy._t1_new OK.
Altering new table...
Altered `dyy`.`_t1_new` OK.
--09T23:: Creating triggers...
--09T23:: Created triggers OK.
--09T23:: Copying approximately rows...
--09T23:: Copied rows OK.
--09T23:: Swapping tables...
--09T23:: Swapped original and new tables OK.
--09T23:: Dropping old table...
--09T23:: Dropped old table `dyy`.`_t1_old` OK.
--09T23:: Dropping triggers...
--09T23:: Dropped triggers OK.
Successfully altered `dyy`.`t1`.
[root@yayun-mysql-server ~]#

可以看见已经成功了。现在需要做的是对大表做一下测试,比如添加索引,添加字段是否会导致锁表。这里用的测试表还是前面文章提到的sysbench生成的1000w数据
session 1

[root@yayun-mysql-server ~]# pt-online-schema-change --alter="add column name char(20) not null default 'yayun'" --user=root D=sbtest,t=sbtest --execute
Operation, tries, wait:
copy_rows, , 0.25
create_triggers, ,
drop_triggers, ,
swap_tables, ,
update_foreign_keys, ,
Altering `sbtest`.`sbtest`...
Creating new table...
Created new table sbtest._sbtest_new OK.
Altering new table...
Altered `sbtest`.`_sbtest_new` OK.
--09T23:: Creating triggers...
--09T23:: Created triggers OK.
--09T23:: Copying approximately rows...
Copying `sbtest`.`sbtest`: % : remain
Copying `sbtest`.`sbtest`: % : remain

session 2

root@localhost : sbtest 23:55:40> select * from sbtest where id=100;
+-----+---+---+----------------------------------------------------+
| id | k | c | pad |
+-----+---+---+----------------------------------------------------+
| 100 | 0 | | qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt |
+-----+---+---+----------------------------------------------------+
1 row in set (0.00 sec) root@localhost : sbtest 23:55:44> select * from sbtest where id=100;
+-----+---+---+----------------------------------------------------+
| id | k | c | pad |
+-----+---+---+----------------------------------------------------+
| 100 | 0 | | qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt |
+-----+---+---+----------------------------------------------------+
1 row in set (0.00 sec) root@localhost : sbtest 23:56:03> select * from sbtest where id=1000;
+------+---+---+----------------------------------------------------+
| id | k | c | pad |
+------+---+---+----------------------------------------------------+
| 1000 | 0 | | qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt |
+------+---+---+----------------------------------------------------+
1 row in set (0.00 sec) root@localhost : sbtest 23:56:09> delete from sbtest where id=1000;
Query OK, 1 row affected (0.77 sec) root@localhost : sbtest 23:56:25> update sbtest set k=100 where id=100;
Query OK, 1 row affected (0.50 sec)
Rows matched: 1 Changed: 1 Warnings: 0 root@localhost : sbtest 23:57:02>

发现DML操作依然是没问题的。而且没有oak-online-alter-table那么多限制,最后测试一下在执行alter table之前有一个大的查询,看是否导致锁等待,这个在MySQL 5.6以及oak-online-alter-table都有这个问题。

测试后发现依然存在锁的问题

root@localhost : (none) 00:39:09> show full processlist;
+----+------+-----------+--------+---------+------+---------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------+--------+---------+------+---------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 38 | root | localhost | sbtest | Query | 325 | Sending data | select * from sbtest |
| 39 | root | localhost | NULL | Query | 1 | NULL | show full processlist |
| 40 | root | localhost | sbtest | Query | 36 | Waiting for table metadata lock | CREATE TRIGGER `pt_osc_sbtest_sbtest_del` AFTER DELETE ON `sbtest`.`sbtest` FOR EACH ROW DELETE IGNORE FROM `sbtest`.`__sbtest_new` WHERE `sbtest`.`__sbtest_new`.`id` <=> OLD.`id` |
| 41 | root | localhost | sbtest | Sleep | 310 | | NULL |
+----+------+-----------+--------+---------+------+---------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
4 rows in set (1.28 sec) root@localhost : (none) 00:42:33>

总结:

pt-online-schema-change比oak-online-alter-table工具更好用,并且存在的限制较少,oak-online-alter-table对有外键的表是没有办法的。对于已经执行了大的查询,这时恰好执行ALTER TABLE操作,都会导致锁表。所以一般选择避开业务高峰期执行。所以还是要在业务量较低且没有大查询时执行Online DDL。

参考资料:

http://openarkkit.googlecode.com/svn/trunk/openarkkit/doc/html/oak-online-alter-table.html(自备梯子)

http://www.percona.com/doc/percona-toolkit/2.1/pt-online-schema-change.html

pt-online-schema-change VS oak-online-alter-table的更多相关文章

  1. MySQL--常见ALTER TABLE 操作

    ##================================## ## 修改表的存储引擎 ## SHOW TABLE STATUS LIKE 'TB_001' \G; ALTER TABLE ...

  2. mysql 常见ALTER TABLE操作

    删除列 alter table table-name drop col-name; 增加列(单列) alter table table-name add col-name col-type comme ...

  3. Online Schema Change for MySQL

    It is great to be able to build small utilities on top of an excellent RDBMS. Thank you MySQL. This ...

  4. AppBoxFuture(四). 随需而变-Online Schema Change

      需求变更是信息化过程中的家常便饭,而在变更过程中如何尽可能小的影响在线业务是比较头疼的事情.举个车联网监控的例子:原终端设备上传车辆的经纬度数据,新的终端设备支持同时上传速度数据,而旧的车辆状态表 ...

  5. schema change + ogg 变更手册

    Check OGG  until no data queuing in replication process:testRO:a)login  test5 –l oggmgrb)oggc)#ggsci ...

  6. MySQL ALTER TABLE: ALTER vs CHANGE vs MODIFY COLUMN

    ALTER COLUMN 语法: ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT} 作用: 设置或删除列的默认值.该操作会直接修 ...

  7. problem during schema drop, statement alter table ACT_RU_VARIABLE

    将activiti的databaseSchemaUpdate设置为drop-create抛出DbSqlSession 错误 发布于2015-02-14 16:03:57 浏览7851次 Excepti ...

  8. SQL Server performance for alter table alter column change data type

    最近在搞一个升级脚本,发现有一张业务表中的某些字段长度需要调整,直接使用alter table alter column进行修改发现修改一列要用十几分钟!!!两三个列那用时简直不能容忍啊!google ...

  9. [Hive - LanguageManual] Alter Table/Partition/Column

    Alter Table/Partition/Column Alter Table Rename Table Alter Table Properties Alter Table Comment Add ...

  10. Spark 2.x不支持ALTER TABLE ADD COLUMNS,没关系,我们改进下

    SparkSQL从2.0开始已经不再支持ALTER TABLE table_name ADD COLUMNS (col_name data_type [COMMENT col_comment], .. ...

随机推荐

  1. 【CF960G】Bandit Blues(第一类斯特林数,FFT)

    [CF960G]Bandit Blues(第一类斯特林数,FFT) 题面 洛谷 CF 求前缀最大值有\(a\)个,后缀最大值有\(b\)个的长度为\(n\)的排列个数. 题解 完完全全就是[FJOI] ...

  2. 【BZOJ2427】[HAOI2010]软件安装(动态规划,Tarjan)

    [BZOJ2427][HAOI2010]软件安装(动态规划,Tarjan) 题面 BZOJ 洛谷 题解 看到这类题目就应该要意识到依赖关系显然是可以成环的. 注意到这样一个性质,依赖关系最多只有一个, ...

  3. cf1000C Covered Points Count (差分+map)

    考虑如果数字范围没有这么大的话,直接做一个差分数组就可以了 但现在变大了 所以要用一个map来维护 #include<bits/stdc++.h> #define pa pair<i ...

  4. luogu3305/bzoj3130 费用流 (二分答案+dinic)

    Bob肯定想挑一个流量最大的边,然后把所有的费用都加给它呗 那Alice就让流量最大的边尽量小呗 那就二分一下答案再dinic呗 #include<bits/stdc++.h> #defi ...

  5. Windows 10中设置自动登录

    步骤 使用WinKey+R打开运行,输入netplwiz. 在打开的用户账户对话框-用户选项卡-取消勾选要使用本计算机,用户必须输入用户名和密码(E). 点击应用按钮,在弹出的自动登录对话框中输入相关 ...

  6. 【LOJ#10154】选课

    题目中所说的每门课都可能有先修课,也可能没有先修课,因此课与课之间的关系构成了一颗森林. 这种树上选择若干物品的最优解问题对应着树形背包问题. 阶段:子树的大小 状态:在当前子树中,选取 i 门课能够 ...

  7. Python基础学习(六)

    前几天一直在练手廖雪峰老师的python课程,接下来继续学习,由于面向对象编程这一课相对理论便不在此练手,直接上手面向对象高级编程. 一.使用 __slots__ 一般情况下一个class是可以绑定一 ...

  8. 基于 Django 2.0.4 的 djcelery 配置

    Django Celery 配置实践 所需环境 python 3.5.2 rabbitmq 安装所需的包 pip install -r requirements.txt QuickStart 创建Dj ...

  9. 即将上线的Spark服务器面临的一系列填坑笔记

    即将上线的Spark服务器面临的一系列填坑笔记 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 把kafka和flume倒腾玩了,以为可以轻松一段时间了,没想到使用CDH部署的spa ...

  10. Redis危险命令重命名、禁用

    Redis的危险命令主要有: flushdb,清空数据库 flushall,清空所有记录,数据库 config,客户端连接后可配置服务器 keys,客户端连接后可查看所有存在的键 作为服务端的redi ...