网站首页 > 基础教程 正文
pt(Percona Toolkit)工具是由Percona公司开发的一个用perl语言编写的工具集,包含很多功能,例如在线更改数据表结构,校验主从数据,检查数据库状态,分析慢查询等。Percona Toolkit 是一组高级命令行工具,Percona 支持人员使用它来执行各种难以手动执行的 MySQL、MongoDB和系统任务。
下载地址为:https://www.percona.com/downloads/percona-toolkit/LATEST/
教程地址:https://docs.percona.com/percona-toolkit/
percona的网站国内有时打不开,可以访问国内的清华镜像
https://mirrors.cnnic.cn/percona/tools/yum/release/latest/RPMS/x86_64/
找到最新版本进行下载
一 PT的安装
1. 安装依赖包
yum install perl-DBI
yum install perl-DBD-MySQL
yum install perl-Time-HiRes
yum install perl-IO-Socket-SSL
yum install perl-TermReadKey
yum install perl-Digest-MD5
2. 安装 Percona Toolkit
rpm -ivh percona-toolkit-3.2.1-1.el7.x86_64.rpm
3. 测试是否安装成功
pt-query-digest --help
如果可以正常显示信息,则说明安装成功
二 PT工具的基本使用
下面我们开始学习应用于Mysql的工具的基本使用
1. pt-online-schema-change
这个工具是DBA经常会使用到的一个更改表的工具,在不阻塞读或写的情况下改变表的结构。
基本使用语法为:pt-online-schema-change [OPTIONS] DSN
下面列表列出部分options,更加详细的请使用pt-online-schema-change --help进行查看
OPTIONS | 短操作符 | 类型 | 默认值 | 简要说明 |
--alter | s | 修改语句,不包含ALTER TABLE 关键字。可以包含多个修改语句,使用逗号分隔 | ||
--ask-pass | 连接 MySQL 时提示输入密码。 | |||
--channel | s | 使用复制通道连接到服务器时使用的通道名称。 | ||
--charset | -A | s | 默认字符集。 | |
--[no]check-alter | Yes | 解析--alter 指定的并尝试警告可能的意外行为。 | ||
--[no]check-foreign-keys | Yes | 检查自引用外键。 | ||
--database | -D | s | 连接到这个数据库。 | |
--[no]drop-new-table | Yes | 如果复制原始表失败,则删除新表。 | ||
--[no]drop-old-table | Yes | 重命名后删除原始表。 | ||
--[no]drop-triggers | Yes | 删除旧表上的触发器。 | ||
--dry-run | 创建和更改新表,但不创建触发器、复制数据或替换原始表。 | |||
--execute | 必须指定此选项才能更改表。如果不这样做,则该工具将仅执行一些安全检查并退出。 | |||
--host | -h | s | 连接到主机。 | |
--null-to-not-null | 允许将允许 NULL 值的列修改为不允许它们的列。 | |||
--password | -p | 连接时使用的密码。如果密码包含逗号,它们必须用反斜杠转义 | ||
--port | -P | i | 用于连接的端口号。 | |
--set-vars | a | 个以逗号分隔的 variable=value 对列表中设置 MySQL 变量。 | ||
--socket | -S | 用于连接的套接字文件。 | ||
--user | -u | 如果不是当前用户,则用于登录的用户。 |
OPTIONS:
类型备注:s=string, i=integer, f=float, h/H/a/A=comma-separated list, d=DSN, z=size, m=time
注意:--dry-run与--execute必须指定一个,二者相互排斥。
DSN为要操作的数据库和表。
DSN:
DSN | 简要说明 |
A | 默认字符集。 |
D | 旧表和新表的数据库。 |
F | 仅从给定文件中读取默认选项 |
h | 连接到主机。 |
p | 连接时使用的密码。如果密码包含逗号,它们必须用反斜杠转义 |
P | 用于连接的端口号。 |
S | 用于连接的套接字文件。 |
t | 要更改的表。 |
u | 如果不是当前用户,则用于登录的用户。 |
1.1 工作原理
1) 创建一个和你要执行 alter 操作的表一样的新表
2) 检查修改表的表结构,在新表上执行ALTER TABLE语句
3) 在原表上创建三个触发器分别对于INSERT UPDATE DELETE操作
4) 从原表拷贝数据到新表,在拷贝过程中,对原表的更新操作会写入到新表中
5) copy 完成以后,用rename table 新表代替原表。
6) 删除原表和触发器,完成表结构的修改。
1.2 工具限制
此工具也存在一些如下所示的限制:
1) 原表必须有主键或唯一索引,如果没有,将更改失败。
2) 如果线上的复制环境过滤器操作过于复杂,工具将无法工作。
3) 如果开启复制延迟检查,但主从延迟时,工具将暂停数据拷贝工作。
4) 如果开启主服务器负载检查,但主服务器负载较高时,工具将暂停操作。
5) 当表使用外键时,如果未使用--alter-foreign-keys-method参数,工具将无法执行。
1.3 工具工作分析
下面先通过几种情况,来分析一下它是如何工作的。
1.3.1 有主键PRIMARY KEY的情况:
目前,我们有数据库test,其中有一张表,结构如下:
CREATE TABLE `t_user` (
`id` int NOT NULL,
`nm` varchar(10) DEFAULT NULL,
`address` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
现在,让我们执行如下命令,目的是增加一个字段nickname varchar(20)
pt-online-schema-change --user=root --password=Ygzlpaul*2022 --host=192.168.246.135 --alter "add column nickname varchar(20)" D=test,t=t_user --execute
提示执行成功了,我们先看看是否真的成功了呢?
查看表结构,发现的确执行成功:
接下来,我们看看,通过执行上述命令,数据库究竟做了什么吧
查看一下,目前所有的日志有哪些
SHOW MASTER LOGS;
目前就一个日志文件(这里是为了方便简单理解,做了Reset操作)
现在,执行SHOW BINLOG EVENTS IN 'binlog.000001'; 内容如下图所示:
为方便理解,以下内容,我将仅仅列出End_log_pos及其Info两个列的信息:
1)
End_log_pos: 539
Info: use `test`; CREATE TABLE `test`.`_t_user_new` (
`id` int NOT NULL,
`nm` varchar(10) DEFAULT NULL,
`address` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci /* xid=177 */
解释:建立了一张新表,结构与t_user完全相同
2)
End_log_pos: 768
Info: use `test`; ALTER TABLE `test`.`_t_user_new` add column nickname varchar(20) /* xid=178 */
解释:对新表做Alter,新增列nickname varchar(20)
3)
End_log_pos: 1133
Info: use `test`; CREATE DEFINER=`root`@`%` TRIGGER `pt_osc_test_t_user_del` AFTER DELETE ON `test`.`t_user` FOR EACH ROW DELETE IGNORE FROM `test`.`_t_user_new` WHERE `test`.`_t_user_new`.`id` <=> OLD.`id` /* xid=190 */
解释:在表t_user增加了一个AFTER DELETE 的触发器。请特别注意,连接字段用的是id,用的是主键列,这或许也就解释了,为什么使用pt-online-schema-change的时候,需要表中存在 PRIMARY KEY 或 UNIQUE INDEX的原因。
4)
End_log_pos: 1638
Info: use `test`; CREATE DEFINER=`root`@`%` TRIGGER `pt_osc_test_t_user_upd` AFTER UPDATE ON `test`.`t_user` FOR EACH ROW BEGIN DELETE IGNORE FROM `test`.`_t_user_new` WHERE !(OLD.`id` <=> NEW.`id`) AND `test`.`_t_user_new`.`id` <=> OLD.`id`;REPLACE INTO `test`.`_t_user_new` (`id`, `nm`, `address`) VALUES (NEW.`id`, NEW.`nm`, NEW.`address`);END /* xid=191 */
解释:在表t_user增加了一个AFTER UPDATE 的触发器。
5)
End_log_pos: 2019
Info: use `test`; CREATE DEFINER=`root`@`%` TRIGGER `pt_osc_test_t_user_ins` AFTER INSERT ON `test`.`t_user` FOR EACH ROW REPLACE INTO `test`.`_t_user_new` (`id`, `nm`, `address`) VALUES (NEW.`id`, NEW.`nm`, NEW.`address`) /* xid=192 */
解释:在表t_user增加了一个AFTER INSERT 的触发器。
6)
End_log_pos: 2173
Info: BEGIN
7)
End_log_pos: 2244
Info: table_id: 134 (test._t_user_new)
8)
End_log_pos: 2324
Info: table_id: 134 flags: STMT_END_F
9)
End_log_pos: 2355
Info: COMMIT /* xid=195 */
解释:以上6到9,开启一个事务,进行拷贝数据。对于里面的详细信息,稍候,我们使用mysqlbinlog再来查看一下,这里暂时先跳过。
10)
End_log_pos: 2566
Info: use `test`; ANALYZE TABLE `test`.`_t_user_new` /* pt-online-schema-change */
解释:分析新表
11)
End_log_pos: 2824
Info: use `test`; RENAME TABLE `test`.`t_user` TO `test`.`_t_user_old`, `test`.`_t_user_new` TO `test`.`t_user` /* xid=203 */
解释:重命名原先的目标表名为OLD,同时,修改新建的表名为目标表名。
12)
End_log_pos: 3047
Info: use `test`; DROP TABLE IF EXISTS `_t_user_old` /* generated by server */ /* xid=204 */
解释:删除原表
13)
End_log_pos: 3248
Info: use `test`; DROP TRIGGER IF EXISTS `test`.`pt_osc_test_t_user_del`
解释:删除AFTER DELETE 的触发器
14)
End_log_pos: 3449
Info: use `test`; DROP TRIGGER IF EXISTS `test`.`pt_osc_test_t_user_upd`
解释:删除AFTER UPDATE 的触发器
15)
End_log_pos: 3650
Info: use `test`; DROP TRIGGER IF EXISTS `test`.`pt_osc_test_t_user_ins`
解释:删除AFTER INSERT 的触发器
上面6)到7)具体日志记录了什么?
现在,就让我们使用mysqlbinlog再查看一下前面涉及到数据的部分的日志是如何的?
mysqlbinlog --base64-output=DECODE-ROWS -v --start-position=2173 --stop-position=2355 /var/lib/mysql/binlog.000001
从上面的截图可以看到记录了一系列insert语句(binlog_format=ROW)。
总结:从上面的日志分析,我们也可以得出其工作原理,及其执行步骤究竟是怎么样的。
1.3.2 无主键,有唯一索引UNIQUE KEY的情况:一个字段构成唯一索引:
目前,我们有数据库test,其中有一张表t_prj,结构如下:
CREATE TABLE `t_prj` (
`prjid` int NOT NULL,
`prjname` varchar(20) DEFAULT NULL,
`prjad` varchar(20) DEFAULT NULL,
UNIQUE KEY `uidx_id` (`prjid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
我们仍然是增加一个字段,看看与有主键(PRIMARY KEY)有什么相同或者不同之处。
pt-online-schema-change --user=root --ask-pass --host=192.168.246.135 --alter "add column prjph tinyint" D=test,t=t_prj --execute
注:此次我们采用--ask-pass,需要输入密码,而不再以明文形式提供
我们跳过检查表结构环节,直接执行SHOW BINLOG EVENTS IN 'binlog.000001'; 查看日志内容,如下图所示:
仔细对比查看,发现与前面有主键(PRIMARY KEY)的执行步骤一致,这里就不再详细解释,唯一需要注意的地方就是,触发器的where条件引用的是唯一索引字段:`prjid`
对于上面的例子,唯一索引是一个字段构成的,那么,假设,我们更改为2个或2个以上字段构成唯一索引呢?
1.3.3 无主键,有唯一索引UNIQUE KEY的情况:三个字段构成唯一索引:
目前,我们有数据库test,其中有一张表t_pfs,结构如下:
CREATE TABLE `t_pfs` (
`pid` smallint NOT NULL,
`fid` smallint NOT NULL,
`sid` smallint NOT NULL,
`note` varchar(20) DEFAULT NULL,
UNIQUE KEY `uidx` (`pid`,`fid`,`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
继续增加一个字段,看看与有唯一索引UNIQUE KEY的情况:一个字段构成唯一索引有什么不同之处。
pt-online-schema-change --user=root --ask-pass --host=192.168.246.135 --alter "add column prjph tinyint" D=test,t=t_pfs --execute
仔细对比,发现触发器的where条件引用的是构成唯一索引字段的所有字段,
我截取其中的部分信息如下:
`test`.`_t_pfs_new`.`pid` <=> OLD.`pid` AND `test`.`_t_pfs_new`.`fid` <=> OLD.`fid` AND `test`.`_t_pfs_new`.`sid` <=> OLD.`sid`
1.3.4 有主键,也有唯一索引
那如果主键,唯一索引都有,是使用主键字段做where?还是唯一索引字段做where呢?
目前,我们有数据库test,其中有一张表t_prjo,结构如下:
CREATE TABLE `t_prjo` (
`id` int NOT NULL,
`prjid` int NOT NULL,
`prjname` varchar(20) DEFAULT NULL,
`prjad` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uidx_id` (`prjid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
继续增加一个字段
pt-online-schema-change --user=root --ask-pass --host=192.168.246.135 --alter "add column prjph tinyint" D=test,t=t_prjo --execute
仔细对比,发现,触发器的where条件引用的是构成主键的字段,
我截取其中的部分信息如下:
`test`.`_t_prjo_new`.`id` <=> OLD.`id` /* xid=201 */
这里也就说明,主键优先级高于唯一索引,优先构成Where的条件。
1.3.5 没有主键,没有唯一索引
我们接下来看看,既没有主键,也没有唯一索引的情况下,工具的表现是如何的。
目前,我们有数据库test,其中有一张表t_nm,结构如下:
CREATE TABLE `t_nm` (
`nm` varchar(10) DEFAULT NULL,
`address` varchar(20) DEFAULT NULL,
`pw` tinyint DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
继续增加一个字段,看看没有主键,没有唯一索引的情况会发生什么。
pt-online-schema-change --user=root --ask-pass --host=192.168.246.135 --alter "add column prjph tinyint" D=test,t=t_nm --execute
结果,发现执行失败,有如下提示信息:
The new table `test`.`_t_nm_new` does not have a PRIMARY KEY or a unique index which is required for the DELETE trigger.
Please check you have at least on UNIQUE and NOT NULLABLE index.
提示信息很明确,执行pt-online-schema-change,需要表最少有一个不能NULL的唯一键存在。
1.3.6 无主键,有多个唯一索引UNIQUE KEY的情况:
这里,我们测试一下如果存在多个唯一索引的情况,看看where条件是用的什么?
目前,我们有数据库test,其中有一张表t_nm,结构如下:
CREATE TABLE `t_pfs_dt` (
`pid` smallint NOT NULL,
`fid` smallint NOT NULL,
`sid` smallint NOT NULL,
`note` varchar(20) DEFAULT NULL,
UNIQUE KEY `uidx_1` (`pid`),
UNIQUE KEY `uidx_2` (`fid`),
UNIQUE KEY `uidx_3` (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
这里增加一个字段,同时删除一个字段:
pt-online-schema-change --user=root --ask-pass --host=192.168.246.135 --alter "add column prjph tinyint default 0,drop column note" D=test,t=t_pfs_dt --execute
仔细对比,发现触发器的where条件引用的是构成唯一索引uidx_1的字段pid,
我截取其中的部分信息如下:
`test`.`_t_pfs_dt_new`.`pid` <=> OLD.`pid`
假如我们将唯一索引做如下调整
CREATE TABLE `t_pfs_dt_a` (
`pid` smallint NOT NULL,
`fid` smallint NOT NULL,
`sid` smallint NOT NULL,
`note` varchar(20) DEFAULT NULL,
UNIQUE KEY `uidx_2` (`pid`), -- 由原来的uidx_1改为uidx_2
UNIQUE KEY `uidx_1` (`fid`), -- 由原来的uidx_2改为uidx_1
UNIQUE KEY `uidx_3` (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
再次执行上述修改命令
pt-online-schema-change --user=root --ask-pass --host=192.168.246.135 --alter "add column prjph tinyint default 0,drop column note" D=test,t=t_pfs_dt_a --execute
再查看日志,发现触发器的where条件引用的是构成唯一索引uidx_1的字段fid:
`test`.`_t_pfs_dt_a_new`.`fid` <=> OLD.`fid`
大胆猜测,应该是多个唯一索引的情况下,会选择索引排序排第一的唯一索引字段做为Where字段。大家如果有兴趣,也可以试试。
1.4 基本使用样例
1.4.1 新增列
pt-online-schema-change --user=root --ask-pass --host=192.168.246.135 --alter "add column prjph tinyint" D=test,t=t_pfs --execute
1.4.2 删除列
pt-online-schema-change --user=root --ask-pass --host=192.168.246.135 --alter "drop column nickname" D=test,t=t_user --execute
1.4.3 新增列(有缺省值),并删除列等多个操作
pt-online-schema-change --user=root --ask-pass --host=192.168.246.135 --alter "add column prjph tinyint default 0,drop column note" D=test,t=t_pfs_dt_a --execute
1.4.4 增加索引
pt-online-schema-change --user=root --ask-pass --host=192.168.246.135 --alter "add key idx_nm(nm)" D=test,t=t_user --execute
1.4.5 增加索引,并新增列
pt-online-schema-change --user=root --ask-pass --host=192.168.246.135 --alter "add column prjph tinyint default 0,add key idx_nm(nm)" D=test,t=t_user --execute
1.4.6 修改字段长度,类型
pt-online-schema-change --user=root --ask-pass --host=192.168.246.135 --alter "modify column prjph bigint,modify column note varchar(15)" D=test,t=t_pfs--execute
1.4.7 修改表引擎
pt-online-schema-change --user=root --ask-pass --host=192.168.246.135 --alter "ENGINE=InnoDB" D=test,t=t_my--execute
1.4.8 删除外键
test库下存在如下表:
CREATE TABLE `t_goods` (
`goodid` int NOT NULL,
`goodname` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
PRIMARY KEY (`goodid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `t_goods_dt` (
`goodsid` int DEFAULT NULL,
`typeid` tinyint DEFAULT NULL,
`id` int NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
KEY `fk_goodsid` (`goodsid`),
CONSTRAINT `fk_goodsid` FOREIGN KEY (`goodsid`) REFERENCES `t_goods` (`goodid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
pt-online-schema-change --user=root --ask-pass --host=192.168.246.135 --alter "DROP FOREIGN KEY _fk_goodsid" D=test,t=t_goods_dt--execute
注意:删除外键约束时,外键约束名称必须添加前导下划线 _
猜你喜欢
- 2025-01-24 MySQL 归档数据的方法你知道了吗(mysql有归档日志吗)
- 2025-01-24 支付宝核心系统都在用的兼容Java的脚本语言
- 2025-01-24 php常用函数在线对照表手册(php 函数)
- 2025-01-24 AlpineLinux安装部署MariaDB(mariadb linux安装)
- 2025-01-24 【2024年终总结】2024年最值得读的 AI 论文
- 2025-01-24 大厂都在用的MySQL主从复制、读写分离及高可用方案
- 2025-01-24 Java 的完整故事,从 1991 年到 2022 年
- 2025-01-24 为什么Java、Python会成为程序员最害怕的编程语言?
- 2025-01-24 作为世界上最好的语言——PHP 到底好在哪
- 2025-01-24 【Linux知识】Linux下快速删除大量文件/文件夹方法
- 最近发表
- 标签列表
-
- gitpush (61)
- pythonif (68)
- location.href (57)
- tail-f (57)
- pythonifelse (59)
- deletesql (62)
- c++模板 (62)
- css3动画 (57)
- c#event (59)
- linuxgzip (68)
- 字符串连接 (73)
- nginx配置文件详解 (61)
- html标签 (69)
- c++初始化列表 (64)
- exec命令 (59)
- canvasfilltext (58)
- mysqlinnodbmyisam区别 (63)
- arraylistadd (66)
- node教程 (59)
- console.table (62)
- c++time_t (58)
- phpcookie (58)
- mysqldatesub函数 (63)
- window10java环境变量设置 (66)
- c++虚函数和纯虚函数的区别 (66)