https://blog.csdn.net/lizarel/article/details/113242838
一、pt-online介绍
pt-online-schema-change是percona公司开发的一个工具,在percona-toolkit包里面可以找到这个功能,它可以在线修改表结构
原理:
首先它会新建一张一模一样的表,表名一般是_new后缀
然后在这个新表执行更改字段操作
然后在原表上加三个触发器,DELETE/UPDATE/INSERT,将原表中要执行的语句也在新表中执行
最后将原表的数据拷贝到新表中,然后替换掉原表
使用pt-online-schema-change执行SQL的日志 SQL语句:
ALTER TABLE `tmp_task_user` ADD support tinyint(1) unsigned NOT NULL DEFAULT '1';
sh pt.sh tmp_task_user "ADD COLUMN support tinyint(1) unsigned NOT NULL DEFAULT '1'"
好处:
降低主从延时的风险
可以限速、限资源,避免操作时MySQL负载过高
建议:
在业务低峰期做,将影响降到最低
限制条件
操作期间,文件系统空间消耗会增加一倍,因为要复制一张表,
是因为pt 要求被作用的表需要含有主键或者唯一索引
##使用create as select * from table ,不会创建索引,因为pt-online-schema-change修改表,要求表必须有主键,所以改用swbench 创建带索引的大表对数据操作
##执行修改命令报错:There is no good index and the table is oversized.
##pt-online-schema-change检查发现:这是因为pt 要求被作用的表需要含有主键或者唯一索引
###Cannot chunk the original table `metas`.`PART`: There is no good index and the table is oversized. at /usr/bin/pt-online-schema-change line 5970.
二、pt-online安装
1.去官网下载对应的版本,官网下载地址:https://www.percona.com/downl…
2.下载解压之后就可以看到pt-online-schema-change
先安装依赖:
yum -y install perl-DBI perl-DBD-MySQL perl-Digest-MD5 perl-IO-Socket-SSL perl-TermReadKey
rpm -ivh percona-toolkit-3.3.0-1.el7.x86_64.rpm
验证
pt-online-schema-change --help
1
三、pt-online-schema-change使用
1.参数 ./bin/pt-online-schema-change --help 可以查看参数的使用,我们只是要修改个表结构,只需要知道几个简单的参数就可以了
–user= 连接mysql的用户名
–password= 连接mysql的密码
–host= 连接mysql的地址
P=3306 连接mysql的端口号
D= 连接mysql的库名
t= 连接mysql的表名
–alter 修改表结构的语句
–execute 执行修改表结构
–charset=utf8 使用utf8编码,避免中文乱码
–no-version-check 不检查版本,在阿里云服务器中一般加入此参数,否则会报错
2.执行
pt-online-schema-change --user=root --password=123456 --host=127.0.0.1 P=3306,D=test,t=users --charset=utf8 --no-version-check --execute --alter "ADD COLUMN pid int(10) DEFAULT 0"
3.为避免每次都要输入一堆参数,写个脚本复用一下,pt.sh
#!/bin/bash
table=$1
alter_conment=$2
cnn_host='127.0.0.1'
cnn_user='root'
cnn_pwd='123456'
cnn_db='test'
echo "$table"
echo "$alter_conment"
pt-online-schema-change --user=${cnn_user} --password=${cnn_pwd} --host=${cnn_host} P=3306,D=${cnn_db},t=${table} --charset=utf8 --no-version-check --alter "${alter_conment}" --execute
那么该语句可以这么写:
sh pt.sh users "ADD COLUMN sid tinyint(4) DEFAULT 0"
————————————————
版权声明:本文为CSDN博主「菜鸟一直在路上」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lizarel/article/details/113242838
######sample 1; 下面测试 原生的mysql 客户端修改 和pt 工具修改的差异:
分如下场景
场景1:空闲的数据库,进行修改数据字段的操作
场景2:繁忙的数据库,对该表的频繁的dml操作,
综合得知:
原生的alter table 速度会略快于pt工具修改,但是会导致阻塞其他对同样的表dml操作
Pt 工具不会阻塞其他对同样的表dml操作,效率会略微慢20%。
建议使用原生的mysql on-line ddl 语句操作,因为感觉生产的io 和测试的io 不是一个数量级的,
##需要注意的是不要使用create as select * from table ,创建测试表,但是测试表不会创建索引,因为pt 修改表,要求表必须有主键,所以改用swbench 创建带索引的大表对数据操作
##
###
##执行修改命令报错:There is no good index and the table is oversized.
##检查发现:这是因为pt 要求被作用的表需要含有主键或者唯一索引
-> 第二次测试 swbench 创建了1000万数据的大表
create database sysbench_test;
select count(*) from sysbench_test.sbtest1
show create table sysbench_test.sbtest1
CREATE TABLE `sbtest1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`k` int(11) NOT NULL DEFAULT '0',
`c` char(120) NOT NULL DEFAULT '',
`pad` char(60) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `k_1` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=20000001 DEFAULT CHARSET=utf8mb4
----》》》#mysql 客户端操作:
-》场景1:空闲的数据库,进行修改数据字段的操作
-> CHANGE 字段字符编码 ,1000万大表执行时间为26分钟,等待事件为Waiting for table metadata lock,正常
16:24:10
alter table sysbench_test.sbtest1 modify column pad char(60) character set latin1;
mysql> alter table sysbench_test.sbtest1 modify column pad char(60) character set latin1;
Query OK, 0 rows affected (26 min 0.78 sec)
Records: 0 Duplicates: 0 Warnings: 0
-》场景2:繁忙的数据库,对该表的频繁的dml操作,dml操作全部阻塞,等待事件为Waiting for table metadata lock,
同时进行ddl,1000万大表执行时间完成事件31分钟
mysql> alter table sysbench_test.sbtest1 modify column pad char(60) character set latin1;
Query OK, 10002797 rows affected (30 min 44.51 sec)
Records: 10002797 Duplicates: 0 Warnings: 0
----》》》#pt工具修改
-》场景1:空闲的数据库,进行修改数据字段的操作
-》换一种方法是用pt工具修改 字段字符类型,消耗时间为34分钟。虽然事件多出了7分钟,但是影响面比较小,因为这是复制一张新表,然后在复制回原来表,
-》影响原来的表事件不多
sh pt.sh sbtest1 "modify column pad char(60) character set utf8mb4"
脚本如下:
#!/bin/bash
table=$1
alter_conment=$2
cnn_host='127.0.0.1'
cnn_user='root'
cnn_pwd='Admindb'
cnn_db='sysbench_test'
echo "$table"
echo "$alter_conment"
pt-online-schema-change --user=${cnn_user} --password=${cnn_pwd} --host=${cnn_host} P=3306,D=${cnn_db},t=${table} --charset=utf8 --no-version-check --alter "${alter_conment}" --execute
结果如下
[root@sdwsmn2 dba]# sh pt.sh sbtest1 "modify column pad char(60) character set utf8mb4"
sbtest1
modify column pad char(60) character set utf8mb4
No slaves found. See --recursion-method if host sdwsmn2 has slaves.
Not checking slave lag because no slaves were found and --check-slave-lag was not specified.
Operation, tries, wait:
analyze_table, 10, 1
copy_rows, 10, 0.25
create_triggers, 10, 1
drop_triggers, 10, 1
swap_tables, 10, 1
update_foreign_keys, 10, 1
Altering `sysbench_test`.`sbtest1`...
Creating new table...
Created new table sysbench_test._sbtest1_new OK.
Altering new table...
Altered `sysbench_test`.`_sbtest1_new` OK.
2022-05-10T15:53:14 Creating triggers...
2022-05-10T15:53:14 Created triggers OK.
2022-05-10T15:53:14 Copying approximately 9754681 rows...
Copying `sysbench_test`.`sbtest1`: 6% 07:16 remain
Copying `sysbench_test`.`sbtest1`: 11% 07:24 remain
。。。。。
Copying `sysbench_test`.`sbtest1`: 99% 00:09 remain
2022-05-10T16:27:57 Copied rows OK.
2022-05-10T16:27:57 Analyzing new table...
2022-05-10T16:27:57 Swapping tables...
2022-05-10T16:27:58 Swapped original and new tables OK.
2022-05-10T16:27:58 Dropping old table...
2022-05-10T16:27:59 Dropped old table `sysbench_test`.`_sbtest1_old` OK.
2022-05-10T16:27:59 Dropping triggers...
2022-05-10T16:27:59 Dropped triggers OK.
Successfully altered `sysbench_test`.`sbtest1`.
-》场景2:繁忙的数据库,对该表的频繁的dml操作,dml操作不会阻塞,可以正常进行,
同时进行ddl,1000万大表执行时间完成事件41分钟
2022-05-10T17:21:07 Copying approximately 9696990 rows...
2022-05-10T18:00:47 Analyzing new table...
2022-05-10T18:00:48 Swapping tables...
2022-05-10T18:00:49 Swapped original and new tables OK.
2022-05-10T18:00:49 Dropping old table...
2022-05-10T18:00:50 Dropped old table `sysbench_test`.`_sbtest1_old` OK.
2022-05-10T18:00:50 Dropping triggers...
2022-05-10T18:00:50 Dropped triggers OK.
#######sample 3 进一步思考on-line ddl ,和 pt-osc 的区别
https://opensource.actionsky.com/20200916-ddl/
-》如何选择
从原理中,可以看出几个关键点:
-
可以看到 pt-osc、gh-ost、原生 Online DDL copy 方式(实际上是非 Online),都是需要 copy 原表数据到一个新表,这个是非常耗时的;
-
pt-osc 采用触发器实现应用 DDL 期间的 DML, gh-ost 通过 binlog 应用 DDL 期间的 DML,理论上触发器会有一定的负载,且 gh-ost 可以从从库上拉取binlog,对主库的影响更小;
-
原生 Online DDL 中 Inplace 方式,对于 no-rebuild 方式,不需要重建表,只需要修改表的元数据,这个是非常快的;
-
原生 Online DDL 中 Inplace 方式,对于 rebuild 方式,需要重建表,但是也是在 InnoDB 内部完成的,比 copy 的方式要快;
-》因此,总结以下几个选择工具的判断依据:
1. 如果 MySQL 版本是 5.6 之前,不支持 Online DDL,选用第三方工具 pt-osc 或 gh-ost;
2. 如果 MySQL 版本是 5.6 以上,对于使用 copy table 方式的 DDL,不支持 Online,使用第三方工具 pt-osc 或 gh-ost;
3. 对于可以使用 Inplace no-rebuild 方式的 DDL,使用原生 Online DDL;
4. 对于使用 Inplace rebuild table 方式的 DDL,如果想使 DDL 过程更加可控,且对从库延迟比较敏感,使用第三方工具 pt-osc 或 gh-ost,否则使用原生 Online DDL;
5. 对于想减少对主库的影响,实时交互,可以选用 gh-ost;
-》
4.1.1 MySQL 原生 DDL
自 MySQL 5.6 起,MySQL 原生支持 Online DDL,即在执行 DDL 期间允许执行 DML(insert、update、delete)。了解 Online DDL 先了解一下之前 DDL 的 2 种算法 copy 和 inplace。
-》Copy:
1. 按照原表定义创建一个新的临时表
2. 对原表加写锁(禁止 DML,允许 select)
3. 步骤 1)建立的临时表执行 DDL
4. 将原表中的数据 copy 到临时表
5. 释放原表的写锁
6. 将原表删除,并将临时表重命名为原表可见,
采用 copy 方式期间需要锁表,禁止 DML,因此是非 Online 的。
-》比如:删除主键、修改列类型、修改字符集,这些操作会导致行记录格式发生变化(无法通过全量 + 增量实现 Online)。
-》Inplace:在原表上进行更改,不需要生成临时表,不需要进行数据 copy 的过程。根据是否行记录格式,分为两类:
-
rebuild:需要重建表(重新组织聚簇索引)。比如 optimize table、添加索引、添加/删除列、修改列 NULL/NOT NULL 属性等;
-
no-rebuild:不需要重建表,只需要修改表的元数据,比如删除索引、修改列名、修改列默认值、修改列自增值等。
对于 rebuild 方式实现 Online 是通过缓存 DDL 期间的 DML,待 DDL 完成之后,将 DML 应用到表上来实现的。
例如,执行一个 alter table A engine=InnoDB;
重建表的 DDL 其大致流程如下:
1. 建立一个临时文件,扫描表 A 主键的所有数据页;
2. 用数据页中表 A 的记录生成 B+ 树,存储到临时文件中;
3. 生成临时文件的过程中,将所有对 A 的操作记录在一个日志文件(row log)中;
4. 临时文件生成后,将日志文件中的操作应用到临时文件,得到一个逻辑数据上与表 A 相同的数据文件;
5. 用临时文件替换表 A 的数据文件。
说明:1. 在 copy 数据到新表期间,在原表上是加的 MDL 读锁(允许 DML,禁止 DDL)
2. 在应用增量期间对原表加 MDL 写锁(禁止 DML 和 DDL)
3. 根据表A重建出来的数据是放在 tmp_file 里的,这个临时文件是 InnoDB 在内部创建出来的,整个 DDL 过程都在 InnoDB 内部完成。对于 server 层来说,没有把数据挪动到临时表,是一个原地操作,这就是“inplace”名称的来源。
-》测试用例