pt-online-schema-change VS oak-online-alter-table
前言
在上篇文章中提到了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的更多相关文章
- MySQL--常见ALTER TABLE 操作
##================================## ## 修改表的存储引擎 ## SHOW TABLE STATUS LIKE 'TB_001' \G; ALTER TABLE ...
- mysql 常见ALTER TABLE操作
删除列 alter table table-name drop col-name; 增加列(单列) alter table table-name add col-name col-type comme ...
- 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 ...
- AppBoxFuture(四). 随需而变-Online Schema Change
需求变更是信息化过程中的家常便饭,而在变更过程中如何尽可能小的影响在线业务是比较头疼的事情.举个车联网监控的例子:原终端设备上传车辆的经纬度数据,新的终端设备支持同时上传速度数据,而旧的车辆状态表 ...
- schema change + ogg 变更手册
Check OGG until no data queuing in replication process:testRO:a)login test5 –l oggmgrb)oggc)#ggsci ...
- MySQL ALTER TABLE: ALTER vs CHANGE vs MODIFY COLUMN
ALTER COLUMN 语法: ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT} 作用: 设置或删除列的默认值.该操作会直接修 ...
- problem during schema drop, statement alter table ACT_RU_VARIABLE
将activiti的databaseSchemaUpdate设置为drop-create抛出DbSqlSession 错误 发布于2015-02-14 16:03:57 浏览7851次 Excepti ...
- SQL Server performance for alter table alter column change data type
最近在搞一个升级脚本,发现有一张业务表中的某些字段长度需要调整,直接使用alter table alter column进行修改发现修改一列要用十几分钟!!!两三个列那用时简直不能容忍啊!google ...
- [Hive - LanguageManual] Alter Table/Partition/Column
Alter Table/Partition/Column Alter Table Rename Table Alter Table Properties Alter Table Comment Add ...
- Spark 2.x不支持ALTER TABLE ADD COLUMNS,没关系,我们改进下
SparkSQL从2.0开始已经不再支持ALTER TABLE table_name ADD COLUMNS (col_name data_type [COMMENT col_comment], .. ...
随机推荐
- SharePoint 错误集
1. Delete a site collection · Run command : Remove-SPSite –Identity http://ent132.sharepoint.hp.com/ ...
- SpringCloud学习(二)---Eureka
Eureka 重点在使用,概念和源码基本不涉及 Eureka是一个基于REST(REST是HTTP协议的)的服务,主要在亚马逊网络服务(AWS)云中使用,定位服务来进行中间层服务器的均衡负载和故障转移 ...
- Office2016自定义安装
Office2016已经不提供自定义安装功能,而采用C2R安装方式.使用镜像安装时,默认全部安装.想要自定义安装就需要用到微软提供的Office2016部署工具. 步骤 下载并运行微软提供的Offic ...
- Luogu 1525 【NOIP2010】关押罪犯 (贪心,并查集)
Luogu 1525 [NOIP2010]关押罪犯 (贪心,并查集) Description S城现有两座监狱,一共关押着N名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨 ...
- SQL: 从一个表随机读取一行或几行记录的问题
比如ms sql 2000,随机读取了一行记录: SELECT TOP 1 * FROM [tablename] ORDER BY NEWID() 遇到的问题是,如果这个表记录不多,比如几十或几百.几 ...
- Flash10 使用剪贴板得改变程序的写法了
昨天一个客户告诉我,在她的电脑上无法复制图片的链接地址. 一开始,我以为是她操作有误,因为在我们的系统里使用的是一种“双保险”的复制方法. javascript + flash 两种方法来进行复制. ...
- pascal与其它语言代码书写的不同和pascal的快捷键
1.把很多简单语句括起来 begin end; 2.开始,结束 begin end. 3.判断if if (布尔表达式) then begin 语句 end //没有‘:’ else if () b ...
- 2156: 中南大学2018年ACM暑期集训前期训练题集(入门题) D: 机器人的指令
不要用gets!不要用gets!不要用gets! 不要用gets!不要用gets!不要用gets! 不要用gets!不要用gets!不要用gets! 不要用gets!不要用gets!不要用gets! ...
- 高级Linux运维工程师必备技能(扫盲篇)
高级Linux运维工程师必备技能(扫盲篇) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在了解文件系统之前,我们要学习一下磁盘存储数据的方式,大家都知道文件从内存若要持久化存储的 ...
- 附录A Spring Boot应用启动器
spring Boot应用启动器基本的一共有44种,具体如下: 1)spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置.日志和YAML. 2)spring- ...