pt-online-schema-change[实战系列]

官方文档

pt-online-schema-change是个可以不锁表的情况下更改表结构的工具,也可以添加索引,建议在表数据量极大的时候使用

安装

apt install percona-toolkit

准备一个千万行数据的大表

CREATE TABLE person(
    id int NOT NULL AUTO_INCREMENT PRIMARY KEY comment '主键',
    person_id tinyint not null comment '用户id',
    person_name VARCHAR(200) comment '用户名称',
    gmt_create datetime comment '创建时间',
    gmt_modified datetime comment '修改时间'
) comment '人员信息表';

添加一条数据

insert into person values(1, 1,'user_1', NOW(), now());

以下 sql 执行 20 次 约等于 100 万条数据执行 24 次 1600 万条数据

insert into person(id, person_id, person_name, gmt_create, gmt_modified)
select @i:=@i+1,
left(rand()*10,10) as person_id,
concat('user_',@i%2048),
date_add(gmt_create,interval + @i*cast(rand()*100 as signed) SECOND),
date_add(date_add(gmt_modified,interval +@i*cast(rand()*100 as signed) SECOND), interval + cast(rand()*1000000 as signed) SECOND)
from person;

pt-online-schema-change[快问快答]

pt-online-schema-change 添加一列c1

pt-online-schema-change --host=192.168.6.14 --user=root --password=123456 --alter "ADD COLUMN c1 INT" D=t1,t=person --print --execute

--host 主机
--user 账号
--password 密码
--alter 修改表结构语句
D 数据库
t 表
--print 打印工具执行过程
--execute 确认开始

因为表数据量过大,一时半会执行不完,这个时候可以去添加几条新数据,删除几条数据,执行成功,然后等待pt-online-schema-change执行完毕,刷新表发现成功添加字段,刚刚添加的数据也在,删除的数据也不见了

pt-online-schema-change[快问快答]

pt-online-schema-change[快问快答]

流程

  • 检测有没从库,如果有从库,从库也会执行添加字段操作

  • 创建一个新表 _person_new

  • 执行

    ALTER TABLE `t1`.`_person_new` ADD COLUMN c1 INT
  • 创建三个触发器

    #删除操作触发器
    Event : DELETE 
    Name  : pt_osc_t1_person_del 
    SQL   : CREATE TRIGGER `pt_osc_t1_person_del` AFTER DELETE ON `t1`.`person` FOR EACH ROW BEGIN DECLARE CONTINUE HANDLER FOR 1146 begin end; DELETE IGNORE FROM `t1`.`_person_new` WHERE `t1`.`_person_new`.`id` <=> OLD.`id`; END  
    Suffix: del 
    Time  : AFTER 
    #更新操作触发器
    Event : UPDATE 
    Name  : pt_osc_t1_person_upd 
    SQL   : CREATE TRIGGER `pt_osc_t1_person_upd` AFTER UPDATE ON `t1`.`person` FOR EACH ROW BEGIN DECLARE CONTINUE HANDLER FOR 1146 begin end; DELETE IGNORE FROM `t1`.`_person_new` WHERE !(OLD.`id` <=> NEW.`id`) AND `t1`.`_person_new`.`id` <=> OLD.`id`; REPLACE INTO `t1`.`_person_new` (`id`, `person_id`, `person_name`, `gmt_create`, `gmt_modified`) VALUES (NEW.`id`, NEW.`person_id`, NEW.`person_name`, NEW.`gmt_create`, NEW.`gmt_modified`); END  
    Suffix: upd 
    Time  : AFTER 
    #添加操作触发器
    Event : INSERT 
    Name  : pt_osc_t1_person_ins 
    SQL   : CREATE TRIGGER `pt_osc_t1_person_ins` AFTER INSERT ON `t1`.`person` FOR EACH ROW BEGIN DECLARE CONTINUE HANDLER FOR 1146 begin end; REPLACE INTO `t1`.`_person_new` (`id`, `person_id`, `person_name`, `gmt_create`, `gmt_modified`) VALUES (NEW.`id`, NEW.`person_id`, NEW.`person_name`, NEW.`gmt_create`, NEW.`gmt_modified`);END  
    Suffix: ins 
    Time  : AFTER 
  • 从person表拷贝数据到_person_new表

    INSERT LOW_PRIORITY IGNORE INTO `t1`.`_person_new` (`id`, `person_id`, `person_name`, `gmt_create`, `gmt_modified`) SELECT `id`, `person_id`, `person_name`, `gmt_create`, `gmt_modified` FROM `t1`.`person` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= ?)) AND ((`id` <= ?)) LOCK IN SHARE MODE
  • 改名,删除旧表

    #原子操作 person改名 person_old,person_new改名person
    RENAME TABLE `t1`.`person` TO `t1`.`_person_old`, `t1`.`_person_new` TO `t1`.`person`
    #删除表person_old
    DROP TABLE IF EXISTS `t1`.`_person_old`
    #删除触发器
    DROP TRIGGER IF EXISTS `t1`.`pt_osc_t1_person_del`
    DROP TRIGGER IF EXISTS `t1`.`pt_osc_t1_person_upd`
    DROP TRIGGER IF EXISTS `t1`.`pt_osc_t1_person_ins`
  • 结束

注意事项

  • 如果表里面已经添加了触发器,该工具将不会启动,可以尝试用gh-ost工具,一款基于binlog的不锁表修改结构工具
  • 如果表里面有外键,除非你指定–alter-foreign-keys-method参数,否则工具将不会启动
  • 如果表里没有主键或者唯一键,该工具将不会启动
  • 如果表里检测到复制过滤器,该工具将不会启动
  • 如果该工具观察到任何复制延迟的副本,它会暂停数据复制操作
  • 如果检测到服务器负载过大,该工具会暂停或中止其操作。
本作品采用《CC 协议》,转载必须注明作者和本文链接
遇强则强,太强另说
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!