使用pt-online-schema-change在线修改大表

使用场景

在线对MYSQL数据库的维护中,我们经常总会涉及到对数据表进行DDL操作(修改增加字段,索引)的情况,而这操作会对表进行锁表操作,在修改一些小表影响很小,而修改大表时,往往影响业务的正常运转,如表数据量上百万,上千万时候

pt-online-schema-change介绍

工作流程原理

1、首先检查表上各个参数,操作的表必须有主键或则唯一索引,并且不能有触发器,否则报错。
如果存在外键,根据alter-foreign-keys-method参数的值,检测外键相关的表,做相应设置的处理。没有使用 --alter-foreign-keys-method指定特定的值,该工具拒绝执行
2、创建一个和源表表结构一样的临时表,表名一般为_tablename_new
3、执行alter修改临时表你所指定的操作
4、在原表上创建3个DELETE/UPDATE/INSERT对应的触发器(用于copy 数据的过程中,在原表中要执行的语句也在新表中执行)
5、从原表拷贝数据到临时表,拷贝过程中在原表进行的写操作都会更新到新建的临时表
6、如果有外键,则修改外键相关的子表,根据修改后的数据,修改外键关联的子表。
7、rename源数据表为old表,把新表rename为源表名,并将old表删除。
8、删除触发器。

这里删除索引的执行SQL日志

执行语句:
pt-online-schema-change --user=root --password=12345678 --socket=/data/mysql/data/mysql3306.sock D=percona_schema,t=mysql_slow_query_review_history --alter=‘drop key idx_hostname_max_ts_min’ --execute --print --max-lag=10 --check-interval=2 --recursion-method=“hosts” --alter-foreign-keys-method=rebuild_constraints --set-vars innodb_lock_wait_timeout=30000

日志如下:

No slaves found.  See --recursion-method if host mysql1 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
No foreign keys reference `percona_schema`.`mysql_slow_query_review_history`; ignoring --alter-foreign-keys-method.
Altering `percona_schema`.`mysql_slow_query_review_history`...
Creating new table...
CREATE TABLE `percona_schema`.`_mysql_slow_query_review_history_new` (
  `host_max` varchar(64) DEFAULT NULL,
  `user_max` varchar(64) DEFAULT NULL,
  `db_max` varchar(64) DEFAULT NULL,
  `checksum` char(32) NOT NULL,
  `sample` text NOT NULL,
  `ts_min` datetime NOT NULL,
  `ts_max` datetime NOT NULL,
  `ts_cnt` float DEFAULT NULL,
  `Query_time_sum` float DEFAULT NULL,
  `Query_time_min` float DEFAULT NULL,
  `Query_time_max` float DEFAULT NULL,
  `Query_time_pct_95` float DEFAULT NULL,
  `Query_time_stddev` float DEFAULT NULL,
  `Query_time_median` float DEFAULT NULL,
  `Lock_time_sum` float DEFAULT NULL,
  `Lock_time_min` float DEFAULT NULL,
  `Lock_time_max` float DEFAULT NULL,
  `Lock_time_pct_95` float DEFAULT NULL,
  `Lock_time_stddev` float DEFAULT NULL,
  `Lock_time_median` float DEFAULT NULL,
  `Rows_sent_sum` float DEFAULT NULL,
  `Rows_sent_min` float DEFAULT NULL,
  `Rows_sent_max` float DEFAULT NULL,
  `Rows_sent_pct_95` float DEFAULT NULL,
  `Rows_sent_stddev` float DEFAULT NULL,
  `Rows_sent_median` float DEFAULT NULL,
  `Rows_examined_sum` float DEFAULT NULL,
  `Rows_examined_min` float DEFAULT NULL,
  `Rows_examined_max` float DEFAULT NULL,
  `Rows_examined_pct_95` float DEFAULT NULL,
  `Rows_examined_stddev` float DEFAULT NULL,
  `Rows_examined_median` float DEFAULT NULL,
  `Rows_affected_sum` float DEFAULT NULL,
  `Rows_affected_min` float DEFAULT NULL,
  `Rows_affected_max` float DEFAULT NULL,
  `Rows_affected_pct_95` float DEFAULT NULL,
  `Rows_affected_stddev` float DEFAULT NULL,
  `Rows_affected_median` float DEFAULT NULL,
  `Rows_read_sum` float DEFAULT NULL,
  `Rows_read_min` float DEFAULT NULL,
  `Rows_read_max` float DEFAULT NULL,
  `Rows_read_pct_95` float DEFAULT NULL,
  `Rows_read_stddev` float DEFAULT NULL,
  `Rows_read_median` float DEFAULT NULL,
  `Merge_passes_sum` float DEFAULT NULL,
  `Merge_passes_min` float DEFAULT NULL,
  `Merge_passes_max` float DEFAULT NULL,
  `Merge_passes_pct_95` float DEFAULT NULL,
  `Merge_passes_stddev` float DEFAULT NULL,
  `Merge_passes_median` float DEFAULT NULL,
  `InnoDB_IO_r_ops_min` float DEFAULT NULL,
  `InnoDB_IO_r_ops_max` float DEFAULT NULL,
  `InnoDB_IO_r_ops_pct_95` float DEFAULT NULL,
  `InnoDB_IO_r_ops_stddev` float DEFAULT NULL,
  `InnoDB_IO_r_ops_median` float DEFAULT NULL,
  `InnoDB_IO_r_bytes_min` float DEFAULT NULL,
  `InnoDB_IO_r_bytes_max` float DEFAULT NULL,
  `InnoDB_IO_r_bytes_pct_95` float DEFAULT NULL,
  `InnoDB_IO_r_bytes_stddev` float DEFAULT NULL,
  `InnoDB_IO_r_bytes_median` float DEFAULT NULL,
  `InnoDB_IO_r_wait_min` float DEFAULT NULL,
  `InnoDB_IO_r_wait_max` float DEFAULT NULL,
  `InnoDB_IO_r_wait_pct_95` float DEFAULT NULL,
  `InnoDB_IO_r_wait_stddev` float DEFAULT NULL,
  `InnoDB_IO_r_wait_median` float DEFAULT NULL,
  `InnoDB_rec_lock_wait_min` float DEFAULT NULL,
  `InnoDB_rec_lock_wait_max` float DEFAULT NULL,
  `InnoDB_rec_lock_wait_pct_95` float DEFAULT NULL,
  `InnoDB_rec_lock_wait_stddev` float DEFAULT NULL,
  `InnoDB_rec_lock_wait_median` float DEFAULT NULL,
  `InnoDB_queue_wait_min` float DEFAULT NULL,
  `InnoDB_queue_wait_max` float DEFAULT NULL,
  `InnoDB_queue_wait_pct_95` float DEFAULT NULL,
  `InnoDB_queue_wait_stddev` float DEFAULT NULL,
  `InnoDB_queue_wait_median` float DEFAULT NULL,
  `InnoDB_pages_distinct_min` float DEFAULT NULL,
  `InnoDB_pages_distinct_max` float DEFAULT NULL,
  `InnoDB_pages_distinct_pct_95` float DEFAULT NULL,
  `InnoDB_pages_distinct_stddev` float DEFAULT NULL,
  `InnoDB_pages_distinct_median` float DEFAULT NULL,
  `QC_Hit_cnt` float DEFAULT NULL,
  `QC_Hit_sum` float DEFAULT NULL,
  `Full_scan_cnt` float DEFAULT NULL,
  `Full_scan_sum` float DEFAULT NULL,
  `Full_join_cnt` float DEFAULT NULL,
  `Full_join_sum` float DEFAULT NULL,
  `Tmp_table_cnt` float DEFAULT NULL,
  `Tmp_table_sum` float DEFAULT NULL,
  `Tmp_table_on_disk_cnt` float DEFAULT NULL,
  `Tmp_table_on_disk_sum` float DEFAULT NULL,
  `Filesort_cnt` float DEFAULT NULL,
  `Filesort_sum` float DEFAULT NULL,
  `Filesort_on_disk_cnt` float DEFAULT NULL,
  `Filesort_on_disk_sum` float DEFAULT NULL,
  `Bytes_sum` float DEFAULT NULL,
  `Bytes_min` float DEFAULT NULL,
  `Bytes_max` float DEFAULT NULL,
  `Bytes_pct_95` float DEFAULT NULL,
  `Bytes_stddev` float DEFAULT NULL,
  `Bytes_median` float DEFAULT NULL,
  PRIMARY KEY (`checksum`,`ts_min`,`ts_max`),
  KEY `idx_hostname_max_ts_min` (`host_max`,`ts_min`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
Created new table percona_schema._mysql_slow_query_review_history_new OK.
Altering new table...
ALTER TABLE `percona_schema`.`_mysql_slow_query_review_history_new` drop key idx_hostname_max_ts_min
Altered `percona_schema`.`_mysql_slow_query_review_history_new` OK.
2020-06-04T17:22:33 Creating triggers...
2020-06-04T17:22:33 Created triggers OK.
2020-06-04T17:22:33 Copying approximately 12 rows...
INSERT LOW_PRIORITY IGNORE INTO `percona_schema`.`_mysql_slow_query_review_history_new` (`host_max`, `user_max`, `db_max`, `checksum`, `sample`, `ts_min`, `ts_max`, `ts_cnt`, `query_time_sum`, `query_time_min`, `query_time_max`, `query_time_pct_95`, `query_time_stddev`, `query_time_median`, `lock_time_sum`, `lock_time_min`, `lock_time_max`, `lock_time_pct_95`, `lock_time_stddev`, `lock_time_median`, `rows_sent_sum`, `rows_sent_min`, `rows_sent_max`, `rows_sent_pct_95`, `rows_sent_stddev`, `rows_sent_median`, `rows_examined_sum`, `rows_examined_min`, `rows_examined_max`, `rows_examined_pct_95`, `rows_examined_stddev`, `rows_examined_median`, `rows_affected_sum`, `rows_affected_min`, `rows_affected_max`, `rows_affected_pct_95`, `rows_affected_stddev`, `rows_affected_median`, `rows_read_sum`, `rows_read_min`, `rows_read_max`, `rows_read_pct_95`, `rows_read_stddev`, `rows_read_median`, `merge_passes_sum`, `merge_passes_min`, `merge_passes_max`, `merge_passes_pct_95`, `merge_passes_stddev`, `merge_passes_median`, `innodb_io_r_ops_min`, `innodb_io_r_ops_max`, `innodb_io_r_ops_pct_95`, `innodb_io_r_ops_stddev`, `innodb_io_r_ops_median`, `innodb_io_r_bytes_min`, `innodb_io_r_bytes_max`, `innodb_io_r_bytes_pct_95`, `innodb_io_r_bytes_stddev`, `innodb_io_r_bytes_median`, `innodb_io_r_wait_min`, `innodb_io_r_wait_max`, `innodb_io_r_wait_pct_95`, `innodb_io_r_wait_stddev`, `innodb_io_r_wait_median`, `innodb_rec_lock_wait_min`, `innodb_rec_lock_wait_max`, `innodb_rec_lock_wait_pct_95`, `innodb_rec_lock_wait_stddev`, `innodb_rec_lock_wait_median`, `innodb_queue_wait_min`, `innodb_queue_wait_max`, `innodb_queue_wait_pct_95`, `innodb_queue_wait_stddev`, `innodb_queue_wait_median`, `innodb_pages_distinct_min`, `innodb_pages_distinct_max`, `innodb_pages_distinct_pct_95`, `innodb_pages_distinct_stddev`, `innodb_pages_distinct_median`, `qc_hit_cnt`, `qc_hit_sum`, `full_scan_cnt`, `full_scan_sum`, `full_join_cnt`, `full_join_sum`, `tmp_table_cnt`, `tmp_table_sum`, `tmp_table_on_disk_cnt`, `tmp_table_on_disk_sum`, `filesort_cnt`, `filesort_sum`, `filesort_on_disk_cnt`, `filesort_on_disk_sum`, `bytes_sum`, `bytes_min`, `bytes_max`, `bytes_pct_95`, `bytes_stddev`, `bytes_median`) SELECT `host_max`, `user_max`, `db_max`, `checksum`, `sample`, `ts_min`, `ts_max`, `ts_cnt`, `query_time_sum`, `query_time_min`, `query_time_max`, `query_time_pct_95`, `query_time_stddev`, `query_time_median`, `lock_time_sum`, `lock_time_min`, `lock_time_max`, `lock_time_pct_95`, `lock_time_stddev`, `lock_time_median`, `rows_sent_sum`, `rows_sent_min`, `rows_sent_max`, `rows_sent_pct_95`, `rows_sent_stddev`, `rows_sent_median`, `rows_examined_sum`, `rows_examined_min`, `rows_examined_max`, `rows_examined_pct_95`, `rows_examined_stddev`, `rows_examined_median`, `rows_affected_sum`, `rows_affected_min`, `rows_affected_max`, `rows_affected_pct_95`, `rows_affected_stddev`, `rows_affected_median`, `rows_read_sum`, `rows_read_min`, `rows_read_max`, `rows_read_pct_95`, `rows_read_stddev`, `rows_read_median`, `merge_passes_sum`, `merge_passes_min`, `merge_passes_max`, `merge_passes_pct_95`, `merge_passes_stddev`, `merge_passes_median`, `innodb_io_r_ops_min`, `innodb_io_r_ops_max`, `innodb_io_r_ops_pct_95`, `innodb_io_r_ops_stddev`, `innodb_io_r_ops_median`, `innodb_io_r_bytes_min`, `innodb_io_r_bytes_max`, `innodb_io_r_bytes_pct_95`, `innodb_io_r_bytes_stddev`, `innodb_io_r_bytes_median`, `innodb_io_r_wait_min`, `innodb_io_r_wait_max`, `innodb_io_r_wait_pct_95`, `innodb_io_r_wait_stddev`, `innodb_io_r_wait_median`, `innodb_rec_lock_wait_min`, `innodb_rec_lock_wait_max`, `innodb_rec_lock_wait_pct_95`, `innodb_rec_lock_wait_stddev`, `innodb_rec_lock_wait_median`, `innodb_queue_wait_min`, `innodb_queue_wait_max`, `innodb_queue_wait_pct_95`, `innodb_queue_wait_stddev`, `innodb_queue_wait_median`, `innodb_pages_distinct_min`, `innodb_pages_distinct_max`, `innodb_pages_distinct_pct_95`, `innodb_pages_distinct_stddev`, `innodb_pages_distinct_median`, `qc_hit_cnt`, `qc_hit_sum`, `full_scan_cnt`, `full_scan_sum`, `full_join_cnt`, `full_join_sum`, `tmp_table_cnt`, `tmp_table_sum`, `tmp_table_on_disk_cnt`, `tmp_table_on_disk_sum`, `filesort_cnt`, `filesort_sum`, `filesort_on_disk_cnt`, `filesort_on_disk_sum`, `bytes_sum`, `bytes_min`, `bytes_max`, `bytes_pct_95`, `bytes_stddev`, `bytes_median` FROM `percona_schema`.`mysql_slow_query_review_history` LOCK IN SHARE MODE /*pt-online-schema-change 30969 copy table*/
2020-06-04T17:22:33 Copied rows OK.
2020-06-04T17:22:33 Analyzing new table...
2020-06-04T17:22:34 Swapping tables...
RENAME TABLE `percona_schema`.`mysql_slow_query_review_history` TO `percona_schema`.`_mysql_slow_query_review_history_old`, `percona_schema`.`_mysql_slow_query_review_history_new` TO `percona_schema`.`mysql_slow_query_review_history`
2020-06-04T17:22:34 Swapped original and new tables OK.
2020-06-04T17:22:34 Dropping old table...
DROP TABLE IF EXISTS `percona_schema`.`_mysql_slow_query_review_history_old`
2020-06-04T17:22:34 Dropped old table `percona_schema`.`_mysql_slow_query_review_history_old` OK.
2020-06-04T17:22:34 Dropping triggers...
DROP TRIGGER IF EXISTS `percona_schema`.`pt_osc_percona_schema_mysql_slow_query_review_history_del`
DROP TRIGGER IF EXISTS `percona_schema`.`pt_osc_percona_schema_mysql_slow_query_review_history_upd`
DROP TRIGGER IF EXISTS `percona_schema`.`pt_osc_percona_schema_mysql_slow_query_review_history_ins`
2020-06-04T17:22:34 Dropped triggers OK.
Successfully altered `percona_schema`.`mysql_slow_query_review_history`.

参数介绍

这里介绍下上面我使用的几个参数介绍,其他参数你们可以参考下percona官网

–execute 这个参数的作用必须指定此选项才能更改表(默认情况下未启用),该工具支持多种其他措施来防止不必要的负载或其他问题,包括自动检测副本,连接到副本以及安全检查。注意:如果不加这个参数,该工具将仅执行一些安全检查并退出。

–max-lag 这个参数默认值是1s,表示暂停数据复制,直到所有副本的延迟小于此值。在每次数据复制查询(每个数据块)之后,该工具使用Seconds_Behind_Master查看它连接到的所有副本的复制延迟。如果任何副本的滞后时间超过此选项的值,则该工具将休眠–check-interval几秒钟,然后再次检查所有副本。如果指定–check slave lag,则该工具只检查该服务器的延迟,而不是所有服务器。如果要精确控制工具监视的服务器,请使用DSN值–recursion-method。

–check-interval 这个参数默认值是1s表示–max-lag两次检查之间的睡眠时间

–recursion-method 这个参数默认值是processlist,hosts;下面是递归查询方法。
在这里插入图片描述
processlist方法是默认方法,因为SHOW SLAVE HOSTS不可靠。但是,如果服务器使用非标准端口(不是3306),hosts方法可以更好地工作。该工具通常会做正确的事情并查找所有副本,但您可以给出一个首选方法,它将首先使用。hosts方法要求使用report-host、report-port等配置副本。

扫描二维码关注公众号,回复: 11562101 查看本文章

–alter-foreign-keys-method 这个参数是用来当表上有外键时候,如何修改外键,以便它们引用新表。引用要更改的表的外键必须经过特殊处理,以确保它们继续引用正确的表。当该工具重命名原始表以让新表取代它时,外键将“跟随”重命名的表,并且必须更改外键以引用新表。该工具自动确定使用哪种方法最好。如果可能,该工具会使用 rebuild_constraints,否则,将使用drop_swap。

–set-vars 这个参数用来设置mysql的变量值,默认情况下一般设置wait_timeout、innodb_lock_wait_timeout 、lock_wait_timeout 这个几个,同时多个写可以使用逗号隔开。

–check-slave-lag 这个参数在有主从环境使用会检查主从延迟。参数说明是 暂停数据复制,直到此副本的滞后时间小于–max-lag。该值是一个DSN从连接选项继承属性(–port,–user等)。此选项将覆盖在所有连接的副本上查找并持续监视复制滞后的正常行为。


考虑从库延迟情况 ,要注意这几个选项的设置
–max-lag
–check-interval
–recursion-method
–check-slave-lag

下面写下有几个参数比较重要的,

–charset=utf8 连接到MySQL后运行SET NAMES UTF8 ,默认使用库字符集

–dry-run 这个参数不建立触发器,不拷贝数据,也不会替换原表。只是创建和更改新表。

–critical-load 默认值:Threads_running = 50
每次chunk操作前后,会根据show global status统计指定的状态量的变化,默认是统计Thread_running。目的是为了安全,防止原始表上的触发器引起负载过高。这也是为了防止在线DDL对线上的影响。超过设置的阀值,就会终止操作,在线DDL就会中断。提示的异常如上报错信息。该选项接受以逗号分隔的MySQL状态变量和阈值列表。可选变量=MAX_VALUE(或:MAX_VALUE)可以跟在每个变量之后。如果未给出,该工具将通过在启动时检查当前值并将其加倍来确定阈值。

–max-load 默认值:Threads_running = 25
在每次chunk操作后,检查show global status状态值是否高于指定的阀值。该参数接受一个mysql status状态变量以及一个阀值,如果没有给定阀值,则定义一个阀值为为高于当前值的20%。注意这个参数不会像–critical-load终止操作,而只是暂停操作。当status值低于阀值时,则继续往下操作。该选项接受以逗号分隔的MySQL状态变量列表。可选变量=MAX_VALUE(或:MAX_VALUE)可以跟在每个变量之后。如果未给出,该工具将通过检查当前值并将其增加20%来确定阈值。

例如,如果您希望该工具在Threads_connected变得太高时暂停,则可以指定“ Threads_connected”,该工具将在开始工作时检查当前值并将该值加20%。如果当前值为100,则当Threads_connected超过120时该工具将暂停,并在再次低于120时恢复工作。如果要指定一个显式阈值,例如110,则可以使用“ Threads_connected:110”或“ Threads_connected = 110”。

此选项的目的是防止工具向服务器添加过多的负载。如果数据复制查询是侵入性的,或者它们导致锁定等待,则服务器上的其他查询将倾向于阻塞和排队。这通常会导致Threads_running增加,并且该工具可以通过在每个查询完成后立即运行SHOW GLOBAL STATUS来检测到该情况。如果为此变量指定阈值,则可以指示该工具等待,直到查询再次正常运行。但是,这不会阻止排队。它只会使服务器有机会从队列中恢复。如果您发现排队,则最好减少组块时间。

–check-replication-filters 检查复制中是否设置了过滤条件,如果设置了,程序将退出
–nocheck-replication-filters 不检查复制中是否设置了过滤条件

举例

删除索引
pt-online-schema-change --user=root–password=12345678 --socket=/data/mysql/data/mysql3306.sock D=percona_schema,t=mysql_slow_query_review_history --alter=‘drop key idx_hostname_max_ts_min’ --execute --print --max-lag=10 --check-interval=2 --recursion-method=“hosts” --alter-foreign-keys-method=rebuild_constraints --set-vars innodb_lock_wait_timeout=30000

添加索引
pt-online-schema-change --user=system --password=12345678 --socket=/data/mysql/data/mysql3306.sock D=percona_schema,t=mysql_slow_query_review_history --alter=‘add key idx_hostname_max_ts_min(host_max,ts_min)’ --execute --print --max-lag=10 --check-interval=2 --check-slave-lag=h=192.168.11.12,u=system,p=12345678,P=3306 --alter-foreign-keys-method=rebuild_constraints --set-vars innodb_lock_wait_timeout=30000

添加字段
pt-online-schema-change --user=root --password=12345678 --socket=/data/mysql/data/mysql3306.sock D=percona_schema,t=mysql_slow_query_review_history --alter=‘add column id bigint(20) AUTO_INCREMENT’ --execute --print --max-load=Threads_connected:800 --critical-load=Threads_running=700 --charset=utf8 --nocheck-replication-filters --max-lag=10 --check-interval=2 --recursion-method=“hosts” --alter-foreign-keys-method=rebuild_constraints --set-vars innodb_lock_wait_timeout=30000

删除字段
pt-online-schema-change --user=root–password=12345678 --socket=/data/mysql/data/mysql3306.sock D=percona_schema,t=mysql_slow_query_review_history --alter='drop column id ’ --execute --print --max-load=Threads_connected:800 --critical-load=Threads_running=700 --charset=utf8 --nocheck-replication-filters --alter-foreign-keys-method=rebuild_constraints --set-vars innodb_lock_wait_timeout=30000

修改字段
pt-online-schema-change --user=root–password=12345678 --socket=/data/mysql/data/mysql3306.sock D=percona_schema,t=mysql_slow_query_review_history --alter=‘modify column id bigint(30) AUTO_INCREMENT’’ --execute --print --max-load=Threads_connected:800 --critical-load=Threads_running=700 --charset=utf8 --nocheck-replication-filters --alter-foreign-keys-method=rebuild_constraints --set-vars innodb_lock_wait_timeout=30000

pt-online-schema-change 好处

  1. 降低主从延时的风险
  2. 可以限速、限资源(CPU,线程数),避免操作时MySQL负载过高导致业务影响

最后建议大家最好还是在业务低峰期做,将影响降到最低。

(以上如有错误,欢迎指出,谢谢!)

猜你喜欢

转载自blog.csdn.net/j_ychen/article/details/106555449
今日推荐