【工具】在线DDL工具 pt-online-schema-change

[TOC]

1-概述

pt-online-schema-change 它可以做到在修改表结构的同时(即进行DDL操作)不阻塞数据库表DML的进行,这样降低了对生产环境数据库的影响。在MySQL5.6之前是不支持Online DDL特性的,在修改表字段的时候会有锁表并阻止表的DML操作,pt-online-schema-change工具在没有Online DDL时解决了这一问题。
当前大部分工作都能使用Online DDL进行操作

官方文档:https://www.percona.com/doc/percona-toolkit/LATEST/pt-online-schema-change.html

1.1 工作原理

  1. 查询当前数据库服务器信息,包括参数设置,负载信息等,判断表是否有存在触发器,是否有外键关联;
  2. 创建一张与旧表结构相同的新表,表名为_旧表名
  3. 在新创建的表上做变更操作;
  4. 旧表上创建DELETEUPDATEINSERT3个触发器;
  5. 拷贝旧表数据到新表上,以chunk为单位进行,拷贝期间涉及的行会持有共享读锁;
  6. 拷贝期间如果旧表如有DML操作,则通过触发器更新同步到新表上;
  7. 当拷贝数据完成之后旧表与新表进行重命名;
  8. 如果有涉及到外键,根据工具指定选项进行外键处理;
  9. 删除旧表;
  10. 删除旧表上触发器。

2-安装

2.1-下载

下载工具包,里面包含所有pt工具集

# 下载地址
https://www.percona.com/downloads/percona-toolkit/LATEST

# 下载
wget https://www.percona.com/downloads/percona-toolkit/3.2.0/binary/redhat/7/x86_64/percona-toolkit-3.2.0-1.el7.x86_64.rpm

2.2-安装

rpm -ivh percona-toolkit-3.2.0-1.el7.x86_64.rpm

3-使用限制与建议

3.1-限制

  1. 被执行变更的表有主键或唯一键,否则会执行失败
  2. 如果检测到表有外键约束,则需要添加--alter-foreign-keys-method选项,否则不会执行
  3. 如果检测到主从复制中存在过滤,则工具不会执行,参考选项--[no]check-replication-filters说明;
  4. 如果检测到主从复制有延迟,则工具有可能会暂停数据拷贝,参考选项--max-lag说明;
  5. 如果检测到连接当前服务器负载过高,则工具有可能暂停执行或中止退出,参考选项--max-load--critical-load说明。
  6. 源表上不要有触发器
  7. 在配置从库延迟检查时候--check-slave-lag,需要配置--max-lag,延迟低于--max-lag时才继续工作,否则暂停

3.2-建议

  1. 如果MySQL支持Online DDL特性,优先考虑使用Online DDL
  2. 如果MySQL版本不支持Online DDL特性,比如早于5.6版本的MySQL,则使用pt-online-schema-change工具
  3. 如果DDL语句在使用Online DDL时需要进行COPY TABLE操作,建议使用pt-online-schema-change工具,因为期间支持DML操作
  4. 如果表存在触发器的情况下,优先使用Online DDL,对于MySQL5.7.2之后版本则可以pt-online-schema-change工具并通过指定选项--preserve-triggers
  5. 如果涉及外键关联的表,优先考虑使用Online DDL

Online DDL :https://dev.mysql.com/doc/refman/5.7/en/innodb-online-ddl-operations.html

4-使用示例

常用参数介绍

名称 描述
--dry-run 这个参数不建立触发器,不拷贝数据,也不会替换原表。只是创建和更改新表。
--execute 这个参数的作用和前面工作原理的介绍的一样,会建立触发器,来保证最新变更的数据会影响至新表。
注意:如果不加这个参数,这个工具会在执行一些检查后退出。
--critical-load 每次chunk操作前后,会根据show global status统计指定的状态量的变化,默认是统计Thread_running。
目的是为了安全,防止原始表上的触发器引起负载过高。
这也是为了防止在线DDL对线上的影响。
超过设置的阀值,就会终止操作,在线DDL就会中断。提示的异常如上报错信息
--max-load 选项定义一个阀值,在每次chunk操作后,查看show global status状态值是否高于指定的阀值。
该参数接受一个mysql status状态变量以及一个阀值,如果没有给定阀值,则定义一个阀值为为高于当前值的20%。
注意这个参数不会像--critical-load终止操作,而只是暂停操作。
当status值低于阀值时,则继续往下操作。
是暂停还是终止操作这是--max-load和--critical-load的差别
--charset=utf8 连接到MySQL后运行SET NAMES UTF8
--check-replication-filters 检查复制中是否设置了过滤条件,如果设置了,程序将退出
--nocheck-replication-filters 不检查复制中是否设置了过滤条件
--set-vars 设置mysql的变量值
--check-slave-lag 检查主从延迟
--chunk-size 默认值:1000,为每个复制的块选择的行数。
--[no]drop-old-table 默认值:是;重命名后删除原始表。
成功重命名原始表以让新表取代它之后,如果没有错误,该工具将默认删除原始表。
如果有任何错误,该工具会将原始表保留在原位。

注意:如果异常中断,则需要删除原表上已创建的触发器与创建出的新表“_XXXXX”

4.1-测试数据结构

mysql> show create table data_million_small\G
*************************** 1. row ***************************
       Table: data_million_small
Create Table: CREATE TABLE `data_million_small` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` varchar(255) DEFAULT NULL,
  `b` varchar(255) DEFAULT NULL,
  `c` varchar(255) DEFAULT NULL,
  `d` varchar(255) DEFAULT NULL,
  `e` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_a` (`a`)
) ENGINE=InnoDB AUTO_INCREMENT=100001 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> select count(*) from data_million_small;
+----------+
| count(*) |
+----------+
|   100000 |
+----------+
1 row in set (0.01 sec)

mysql> select version();
+------------+
| version()  |
+------------+
| 5.7.25-log |
+------------+
1 row in set (0.00 sec)

4.2-添加字段【可使用Online DDL特性替换】

pt-online-schema-change h=192.168.66.101,P=3306,D=ytest,t=data_million_small --user=root --ask-pass --alter "add comment varchar(50)" --charset=utf8 --execute

限制活跃连接超出25即停止pt-osc操作,--critical-load=Threads_running=25

4.3-修改字段

pt-online-schema-change h=192.168.66.101,P=3306,D=ytest,t=data_million_small --user=root --ask-pass --alter "modify column comment varchar(50) character set utf8mb4" --execute

4.3-删除字段【可使用Online DDL特性替换】

pt-online-schema-change h=192.168.66.101,P=3306,D=ytest,t=data_million_small --user=root --ask-pass --alter "drop column comment,drop column comment2" --execute

4.4-添加索引【可使用Online DDL特性替换】

pt-online-schema-change h=192.168.66.101,P=3306,D=ytest,t=data_million_small --user=root --ask-pass --alter "add index idx_b(b)" --execute

4.5-删除索引【可使用Online DDL特性替换】

pt-online-schema-change h=192.168.66.101,P=3306,D=ytest,t=data_million_small --user=root --ask-pass --alter "drop index idx_b" --execute

4.6-修改字段为null/not null【可使用Online DDL特性替换】

# 改为null
pt-online-schema-change h=192.168.66.101,P=3306,D=ytest,t=data_million_small --user=root --ask-pass --alter "modify column c varchar(255) default null" --execute

# 改为 not null
pt-online-schema-change h=192.168.66.101,P=3306,D=ytest,t=data_million_small --user=root --ask-pass --alter "modify column c varchar(255) not null" --execute

4.7-添加主键【可使用Online DDL特性替换】

pt-online-schema-change h=192.168.66.101,P=3306,D=ytest,t=data_million_small --user=root --ask-pass --alter "add primary key(id)" --execute

4.8-删除主键【锁表,推荐使用pt-online-schema-change】

pt-online-schema-change h=192.168.66.101,P=3306,D=ytest,t=data_million_small --user=root --ask-pass --alter "drop primary key" --execute

4.9-重建表

pt-online-schema-change h=192.168.66.101,P=3306,D=ytest,t=data_million_small --user=root --ask-pass --alter "engine=InnoDB" --execute

4.8-保留变更的新旧表

# 保留旧表
pt-online-schema-change h=192.168.66.101,P=3306,D=ytest,t=data_million_small --user=root --ask-pass --alter "add comment varchar(50)" --no-drop-old-table --execute

# 保留新表,
pt-online-schema-change h=192.168.66.101,P=3306,D=ytest,t=data_million_small --user=root --ask-pass --alter "add comment2 varchar(50)" --no-drop-new-table --no-swap-tables --new-table-name='data_million_small_newt' --execute

5-原理

-- 初始的一些检查数据库参数、负载信息
2020-05-07 10:44:52.164136    453    [email protected] on ytest using TCP/IP
2020-05-07 10:44:52.185222    453    SHOW VARIABLES LIKE 'innodb\_lock_wait_timeout'
2020-05-07 10:44:52.188090    453    SET SESSION innodb_lock_wait_timeout=1
2020-05-07 10:44:52.188617    453    SHOW VARIABLES LIKE 'lock\_wait_timeout'
2020-05-07 10:44:52.190239    453    SET SESSION lock_wait_timeout=60
2020-05-07 10:44:52.190730    453    SHOW VARIABLES LIKE 'wait\_timeout'
2020-05-07 10:44:52.192305    453    SET SESSION wait_timeout=10000
2020-05-07 10:44:52.192933    453    SELECT @@SQL_MODE
2020-05-07 10:44:52.193432    453    SET @@SQL_QUOTE_SHOW_CREATE = 1/*!40101, @@SQL_MODE='NO_AUTO_VALUE_ON_ZERO,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'*/
2020-05-07 10:44:52.193927    453    SELECT VERSION()
2020-05-07 10:44:52.194421    453    SHOW VARIABLES LIKE 'character_set_server'
2020-05-07 10:44:52.196770    453    SELECT @@server_id /*!50038 , @@hostname*/
2020-05-07 10:44:52.198925    454    [email protected] on ytest using TCP/IP
2020-05-07 10:44:52.199614    454    SHOW VARIABLES LIKE 'innodb\_lock_wait_timeout'
2020-05-07 10:44:52.202254    454    SET SESSION innodb_lock_wait_timeout=1
2020-05-07 10:44:52.209802    454    SHOW VARIABLES LIKE 'lock\_wait_timeout'
2020-05-07 10:44:52.212032    454    SET SESSION lock_wait_timeout=60
2020-05-07 10:44:52.212604    454    SHOW VARIABLES LIKE 'wait\_timeout'
2020-05-07 10:44:52.214144    454    SET SESSION wait_timeout=10000
2020-05-07 10:44:52.214597    454    SELECT @@SQL_MODE
2020-05-07 10:44:52.215036    454    SET @@SQL_QUOTE_SHOW_CREATE = 1/*!40101, @@SQL_MODE='NO_AUTO_VALUE_ON_ZERO,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'*/
2020-05-07 10:44:52.215497    454    SELECT VERSION()
2020-05-07 10:44:52.215957    454    SHOW VARIABLES LIKE 'character_set_server'
2020-05-07 10:44:52.217592    454    SELECT @@server_id /*!50038 , @@hostname*/
2020-05-07 10:44:52.218198    453    SHOW VARIABLES LIKE 'wsrep_on'
2020-05-07 10:44:52.220235    453    SHOW VARIABLES LIKE 'version%'
2020-05-07 10:44:52.221924    453    SHOW ENGINES
2020-05-07 10:44:52.222691    453    SHOW VARIABLES LIKE 'innodb_version'
2020-05-07 10:44:52.224824    453    SHOW VARIABLES LIKE 'innodb_stats_persistent'
2020-05-07 10:44:52.226627    453    SELECT @@SERVER_ID
2020-05-07 10:44:52.227133    453    SHOW GRANTS FOR CURRENT_USER()
2020-05-07 10:44:52.227622    453    SHOW FULL PROCESSLIST
2020-05-07 10:44:52.228280    453    SHOW SLAVE HOSTS
2020-05-07 10:44:52.229008    453    SHOW GLOBAL STATUS LIKE 'Threads_running'
2020-05-07 10:44:52.230489    453    SHOW GLOBAL STATUS LIKE 'Threads_running'
2020-05-07 10:44:52.231733    453    SELECT CONCAT(@@hostname, @@port)

-- 查看需要执行变更的表状态
2020-05-07 10:44:52.232574    453    SHOW TABLES FROM `ytest` LIKE 'data\_million\_small'
2020-05-07 10:44:52.233211    453    SELECT VERSION()

-- 查看表是否存在触发器
2020-05-07 10:44:52.233722    453    SHOW TRIGGERS FROM `ytest` LIKE 'data\_million\_small'
2020-05-07 10:44:52.234577    453    /*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, @@SQL_MODE := '', @OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, @@SQL_QUOTE_SHOW_CREATE := 1 */

-- 查看表的建表语句
2020-05-07 10:44:52.235007    453    USE `ytest`
2020-05-07 10:44:52.235498    453    SHOW CREATE TABLE `ytest`.`data_million_small`
2020-05-07 10:44:52.236206    453    /*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, @@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */

-- 查询表的执行计划,确定表是否有外键关联
2020-05-07 10:44:52.237035    453    EXPLAIN SELECT * FROM `ytest`.`data_million_small` WHERE 1=1
2020-05-07 10:44:52.237856    453    SELECT table_schema, table_name FROM information_schema.key_column_usage WHERE referenced_table_schema='ytest' AND referenced_table_name='data_million_small'
2020-05-07 10:44:52.251785    453    SHOW VARIABLES LIKE 'version%'
2020-05-07 10:44:52.254181    453    SHOW ENGINES
2020-05-07 10:44:52.254934    453    SHOW VARIABLES LIKE 'innodb_version'
2020-05-07 10:44:52.256860    453    SELECT table_schema, table_name FROM information_schema.key_column_usage WHERE referenced_table_schema='ytest' AND referenced_table_name='data_million_small'
2020-05-07 10:44:52.266957    453    SHOW VARIABLES LIKE 'wsrep_on'
2020-05-07 10:44:52.286189    453    /*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, @@SQL_MODE := '', @OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, @@SQL_QUOTE_SHOW_CREATE := 1 */
2020-05-07 10:44:52.287559    453    USE `ytest`
2020-05-07 10:44:52.290402    453    SHOW CREATE TABLE `ytest`.`data_million_small`
2020-05-07 10:44:52.293105    453    /*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, @@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */

-- 创建'_'(下划线)开头相同表结构的新表,并先在新表上执行变更操作
2020-05-07 10:44:52.297212    453    CREATE TABLE `ytest`.`_data_million_small_new` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` varchar(255) DEFAULT NULL,
  `b` varchar(255) DEFAULT NULL,
  `c` varchar(255) NOT NULL,
  `d` varchar(255) DEFAULT NULL,
  `e` varchar(255) DEFAULT NULL,
  `comment3` varchar(50) DEFAULT NULL,
  `comment` varchar(50) DEFAULT NULL,
  `comment5` varchar(50) DEFAULT NULL,
  `comment6` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_a` (`a`)
) ENGINE=InnoDB AUTO_INCREMENT=100001 DEFAULT CHARSET
2020-05-07 10:44:52.396325    453    ALTER TABLE `ytest`.`_data_million_small_new` add comment7 varchar(50)
2020-05-07 10:44:52.533918    453    /*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, @@SQL_MODE := '', @OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, @@SQL_QUOTE_SHOW_CREATE := 1 */

-- 查看原表上是否有触发器
2020-05-07 10:44:52.534507    453    USE `ytest`
2020-05-07 10:44:52.535005    453    SHOW CREATE TABLE `ytest`.`_data_million_small_new`
2020-05-07 10:44:52.535651    453    /*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, @@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */
2020-05-07 10:44:52.537445    453    SELECT TRIGGER_SCHEMA, TRIGGER_NAME, DEFINER, ACTION_STATEMENT, SQL_MODE,        CHARACTER_SET_CLIENT, COLLATION_CONNECTION, EVENT_MANIPULATION, ACTION_TIMING   FROM INFORMATION_SCHEMA.TRIGGERS  WHERE EVENT_MANIPULATION = 'DELETE'    AND ACTION_TIMING = 'AFTER'    AND TRIGGER_SCHEMA = 'ytest'    AND EVENT_OBJECT_TABLE = 'data_million_small'
2020-05-07 10:44:52.538626    453    SELECT TRIGGER_SCHEMA, TRIGGER_NAME, DEFINER, ACTION_STATEMENT, SQL_MODE,        CHARACTER_SET_CLIENT, COLLATION_CONNECTION, EVENT_MANIPULATION, ACTION_TIMING   FROM INFORMATION_SCHEMA.TRIGGERS  WHERE EVENT_MANIPULATION = 'UPDATE'    AND ACTION_TIMING = 'AFTER'    AND TRIGGER_SCHEMA = 'ytest'    AND EVENT_OBJECT_TABLE = 'data_million_small'
2020-05-07 10:44:52.539597    453    SELECT TRIGGER_SCHEMA, TRIGGER_NAME, DEFINER, ACTION_STATEMENT, SQL_MODE,        CHARACTER_SET_CLIENT, COLLATION_CONNECTION, EVENT_MANIPULATION, ACTION_TIMING   FROM INFORMATION_SCHEMA.TRIGGERS  WHERE EVENT_MANIPULATION = 'INSERT'    AND ACTION_TIMING = 'AFTER'    AND TRIGGER_SCHEMA = 'ytest'    AND EVENT_OBJECT_TABLE = 'data_million_small'
2020-05-07 10:44:52.540487    453    SELECT TRIGGER_SCHEMA, TRIGGER_NAME, DEFINER, ACTION_STATEMENT, SQL_MODE,        CHARACTER_SET_CLIENT, COLLATION_CONNECTION, EVENT_MANIPULATION, ACTION_TIMING   FROM INFORMATION_SCHEMA.TRIGGERS  WHERE EVENT_MANIPULATION = 'DELETE'    AND ACTION_TIMING = 'BEFORE'    AND TRIGGER_SCHEMA = 'ytest'    AND EVENT_OBJECT_TABLE = 'data_million_small'
2020-05-07 10:44:52.541423    453    SELECT TRIGGER_SCHEMA, TRIGGER_NAME, DEFINER, ACTION_STATEMENT, SQL_MODE,        CHARACTER_SET_CLIENT, COLLATION_CONNECTION, EVENT_MANIPULATION, ACTION_TIMING   FROM INFORMATION_SCHEMA.TRIGGERS  WHERE EVENT_MANIPULATION = 'UPDATE'    AND ACTION_TIMING = 'BEFORE'    AND TRIGGER_SCHEMA = 'ytest'    AND EVENT_OBJECT_TABLE = 'data_million_small'
2020-05-07 10:44:52.542383    453    SELECT TRIGGER_SCHEMA, TRIGGER_NAME, DEFINER, ACTION_STATEMENT, SQL_MODE,        CHARACTER_SET_CLIENT, COLLATION_CONNECTION, EVENT_MANIPULATION, ACTION_TIMING   FROM INFORMATION_SCHEMA.TRIGGERS  WHERE EVENT_MANIPULATION = 'INSERT'    AND ACTION_TIMING = 'BEFORE'    AND TRIGGER_SCHEMA = 'ytest'    AND EVENT_OBJECT_TABLE = 'data_million_small'

-- 在原表上分别创建DELETE、UPDATE、INSERT三个触发器
2020-05-07 10:44:52.543320    453    CREATE TRIGGER `pt_osc_ytest_data_million_small_del` AFTER DELETE ON `ytest`.`data_million_small` FOR EACH ROW DELETE IGNORE FROM `ytest`.`_data_million_small_new` WHERE `ytest`.`_data_million_small_new`.`id` <=> OLD.`id`
2020-05-07 10:44:52.571388    453    CREATE TRIGGER `pt_osc_ytest_data_million_small_upd` AFTER UPDATE ON `ytest`.`data_million_small` FOR EACH ROW BEGIN DELETE IGNORE FROM `ytest`.`_data_million_small_new` WHERE !(OLD.`id` <=> NEW.`id`) AND `ytest`.`_data_million_small_new`.`id` <=> OLD.`id`;REPLACE INTO `ytest`.`_data_million_small_new` (`id`, `a`, `b`, `c`, `d`, `e`, `comment3`, `comment`, `comment5`, `comment6`) VALUES (NEW.`id`, NEW.`a`, NEW.`b`, NEW.`c`, NEW.`d`, NEW.`e`, NEW.`comment3`, NEW.`comment`, NEW.`comment5`, NEW.`co` -- ...略
2020-05-07 10:44:52.596528    453    CREATE TRIGGER `pt_osc_ytest_data_million_small_ins` AFTER INSERT ON `ytest`.`data_million_small` FOR EACH ROW REPLACE INTO `ytest`.`_data_million_small_new` (`id`, `a`, `b`, `c`, `d`, `e`, `comment3`, `comment`, `comment5`, `comment6`) VALUES (NEW.`id`, NEW.`a`, NEW.`b`, NEW.`c`, NEW.`d`, NEW.`e`, NEW.`comment3`, NEW.`comment`, NEW.`comment5`, NEW.`comment6`)

-- 根据执行计划判断chunk包含的行数,以chunk数为单位拷贝数据,为在拷贝过程中为这些行加共享读锁
2020-05-07 10:44:52.621818    453    EXPLAIN SELECT * FROM `ytest`.`data_million_small` WHERE 1=1
2020-05-07 10:44:52.623608    453    SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `ytest`.`data_million_small` FORCE INDEX(`PRIMARY`) ORDER BY `id` LIMIT 1 /*first lower boundary*/
2020-05-07 10:44:52.624543    453    SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `ytest`.`data_million_small` FORCE INDEX (`PRIMARY`) WHERE `id` IS NOT NULL ORDER BY `id` LIMIT 1 /*key_len*/
2020-05-07 10:44:52.625181    453    EXPLAIN SELECT /*!40001 SQL_NO_CACHE */ * FROM `ytest`.`data_million_small` FORCE INDEX (`PRIMARY`) WHERE `id` >= '1' /*key_len*/
2020-05-07 10:44:52.625944    453    EXPLAIN SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `ytest`.`data_million_small` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1')) ORDER BY `id` LIMIT 999, 2 /*next chunk boundary*/
2020-05-07 10:44:52.626592    453    SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `ytest`.`data_million_small` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1')) ORDER BY `id` LIMIT 999, 2 /*next chunk boundary*/
2020-05-07 10:44:52.627433    453    EXPLAIN SELECT `id`, `a`, `b`, `c`, `d`, `e`, `comment3`, `comment`, `comment5`, `comment6` FROM `ytest`.`data_million_small` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1')) AND ((`id` <= '1000')) LOCK IN SHARE MODE /*explain pt-online-schema-change 18112 copy nibble*/
2020-05-07 10:44:52.628189    453    INSERT LOW_PRIORITY IGNORE INTO `ytest`.`_data_million_small_new` (`id`, `a`, `b`, `c`, `d`, `e`, `comment3`, `comment`, `comment5`, `comment6`) SELECT `id`, `a`, `b`, `c`, `d`, `e`, `comment3`, `comment`, `comment5`, `comment6` FROM `ytest`.`data_million_small` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1')) AND ((`id` <= '1000')) LOCK IN SHARE MODE /*pt-online-schema-change 18112 copy nibble*/

-- 每次拷贝完chunk中数据后,查看是否有警告,查看服务器的负载情况,这是在每个chunk拷贝完成后进行的
2020-05-07 10:44:52.681451    453    SHOW WARNINGS
2020-05-07 10:44:52.682218    453    SHOW GLOBAL STATUS LIKE 'Threads_running'
2020-05-07 10:44:52.683950    453    EXPLAIN SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `ytest`.`data_million_small` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1001')) ORDER BY `id` LIMIT 9404, 2 /*next chunk boundary*/
2020-05-07 10:44:52.684658    453    SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `ytest`.`data_million_small` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1001')) ORDER BY `id` LIMIT 9404, 2 /*next chunk boundary*/
2020-05-07 10:44:52.694194    453    EXPLAIN SELECT `id`, `a`, `b`, `c`, `d`, `e`, `comment3`, `comment`, `comment5`, `comment6` FROM `ytest`.`data_million_small` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1001')) AND ((`id` <= '10405')) LOCK IN SHARE MODE /*explain pt-online-schema-change 18112 copy nibble*/
2020-05-07 10:44:52.699243    453    INSERT LOW_PRIORITY IGNORE INTO `ytest`.`_data_million_small_new` (`id`, `a`, `b`, `c`, `d`, `e`, `comment3`, `comment`, `comment5`, `comment6`) SELECT `id`, `a`, `b`, `c`, `d`, `e`, `comment3`, `comment`, `comment5`, `comment6` FROM `ytest`.`data_million_small` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '1001')) AND ((`id` <= '10405')) LOCK IN SHARE MODE /*pt-online-schema-change 18112 copy nibble*/

... 略

2020-05-07 10:44:54.665179    453    INSERT LOW_PRIORITY IGNORE INTO `ytest`.`_data_million_small_new` (`id`, `a`, `b`, `c`, `d`, `e`, `comment3`, `comment`, `comment5`, `comment6`) SELECT `id`, `a`, `b`, `c`, `d`, `e`, `comment3`, `comment`, `comment5`, `comment6` FROM `ytest`.`data_million_small` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= '76055')) AND ((`id` <= '100000')) LOCK IN SHARE MODE /*pt-online-schema-change 18112 copy nibble*/
2020-05-07 10:44:54.997152    453    SHOW WARNINGS
2020-05-07 10:44:54.997953    453    SHOW GLOBAL STATUS LIKE 'Threads_running'

-- 当拷贝数据完成之后,及时分析表进行统计信息的收集
2020-05-07 10:44:55.000173    453    ANALYZE TABLE `ytest`.`_data_million_small_new` /* pt-online-schema-change */

-- 完成旧表与新表的交换
2020-05-07 10:44:55.025956    453    RENAME TABLE `ytest`.`data_million_small` TO `ytest`.`_data_million_small_old`, `ytest`.`_data_million_small_new` TO `ytest`.`data_million_small`
2020-05-07 10:44:55.026906    453    RENAME TABLE `ytest`.`data_million_small` TO `ytest`.`__data_million_small_old`, `ytest`.`_data_million_small_new` TO `ytest`.`data_million_small`

-- 删除旧表
2020-05-07 10:44:55.102094    453    DROP TABLE IF EXISTS `ytest`.`__data_million_small_old`

-- 删除触发器
2020-05-07 10:44:55.140694    453    DROP TRIGGER IF EXISTS `ytest`.`pt_osc_ytest_data_million_small_del`
2020-05-07 10:44:55.153701    453    DROP TRIGGER IF EXISTS `ytest`.`pt_osc_ytest_data_million_small_upd`
2020-05-07 10:44:55.160543    453    DROP TRIGGER IF EXISTS `ytest`.`pt_osc_ytest_data_million_small_ins`
2020-05-07 10:44:55.167288    453    SHOW TABLES FROM `ytest` LIKE '\_data\_million\_small\_new'

工作流程总结:

  1. 查询当前数据库服务器信息,包括参数设置,负载信息等,判断表是否有存在触发器,是否有外键关联;
  2. 创建一张与旧表结构相同的新表,表名为_旧表名
  3. 在新创建的表上做变更操作;
  4. 旧表上创建DELETEUPDATEINSERT3个触发器;
  5. 拷贝旧表数据到新表上,以chunk为单位进行,拷贝期间涉及的行会持有共享读锁;
  6. 拷贝期间如果旧表如有DML操作,则通过触发器更新同步到新表上;
  7. 当拷贝数据完成之后旧表与新表进行重命名;
  8. 如果有涉及到外键,根据工具指定选项进行外键处理;
  9. 删除旧表;
  10. 删除旧表上触发器。

参考:
https://www.cnblogs.com/dbabd/p/10605629.html
https://dev.mysql.com/doc/refman/5.7/en/innodb-online-ddl-operations.html#online-ddl-column-operations

你可能感兴趣的:(【工具】在线DDL工具 pt-online-schema-change)