前言

在上篇文章中提到了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. SharePoint 错误集

    1. Delete a site collection · Run command : Remove-SPSite –Identity http://ent132.sharepoint.hp.com/ ...

  2. SpringCloud学习(二)---Eureka

    Eureka 重点在使用,概念和源码基本不涉及 Eureka是一个基于REST(REST是HTTP协议的)的服务,主要在亚马逊网络服务(AWS)云中使用,定位服务来进行中间层服务器的均衡负载和故障转移 ...

  3. Office2016自定义安装

    Office2016已经不提供自定义安装功能,而采用C2R安装方式.使用镜像安装时,默认全部安装.想要自定义安装就需要用到微软提供的Office2016部署工具. 步骤 下载并运行微软提供的Offic ...

  4. Luogu 1525 【NOIP2010】关押罪犯 (贪心,并查集)

    Luogu 1525 [NOIP2010]关押罪犯 (贪心,并查集) Description S城现有两座监狱,一共关押着N名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨 ...

  5. SQL: 从一个表随机读取一行或几行记录的问题

    比如ms sql 2000,随机读取了一行记录: SELECT TOP 1 * FROM [tablename] ORDER BY NEWID() 遇到的问题是,如果这个表记录不多,比如几十或几百.几 ...

  6. Flash10 使用剪贴板得改变程序的写法了

    昨天一个客户告诉我,在她的电脑上无法复制图片的链接地址. 一开始,我以为是她操作有误,因为在我们的系统里使用的是一种“双保险”的复制方法. javascript + flash 两种方法来进行复制. ...

  7. pascal与其它语言代码书写的不同和pascal的快捷键

    1.把很多简单语句括起来 begin end; 2.开始,结束 begin end. 3.判断if if (布尔表达式) then begin 语句 end  //没有‘:’ else if () b ...

  8. 2156: 中南大学2018年ACM暑期集训前期训练题集(入门题) D: 机器人的指令

    不要用gets!不要用gets!不要用gets! 不要用gets!不要用gets!不要用gets! 不要用gets!不要用gets!不要用gets! 不要用gets!不要用gets!不要用gets! ...

  9. 高级Linux运维工程师必备技能(扫盲篇)

    高级Linux运维工程师必备技能(扫盲篇) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在了解文件系统之前,我们要学习一下磁盘存储数据的方式,大家都知道文件从内存若要持久化存储的 ...

  10. 附录A Spring Boot应用启动器

    spring Boot应用启动器基本的一共有44种,具体如下: 1)spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置.日志和YAML. 2)spring- ...