pt-online-schema-change原理分析

使用pt-online-schema-change工具修改schema时,会先创建一个与原数据表拥有相同结构的新表,然后将原表中的数据逐步复制到新表。

例如一个拥有id,name数据列的zs表,向该表添加名为uid新列时,使用如下命令:

root@localhost:mysql3316.sock  14:24:33 [test]>show create table zsG
*************************** 1. row ***************************
       Table: zs
Create Table: CREATE TABLE `zs` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

root@localhost:mysql3316.sock  14:27:10 [test]>SELECT * FROM zs;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | zhangshuo |
+----+-----------+
1 row in set (0.00 sec)
[root@bogon data]# pt-online-schema-change --alter "add uid int" D=test,t=zs --no-drop-old-table --no-drop-new-table --chunk-size=500 --chunk-size-limit=600 --defaults-file=/usr/local/mysql/my3316.cnf --host=localhost --port=3316 --charset=utf8 --user=root --ask-pass --progress=time,30 --max-load="threads_running=100" --critical-load="threads_running=1000" --chunk-index=PRIMARY --execute

1.pt-online-schema-change处理上述命令时,会 先根据原zs数据表的结构创建新表,(_zs_new),并将要添加的列加到新表:

58 Query     SHOW VARIABLES LIKE 'wsrep_on'
                   58 Query     /*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, @@SQL_MODE := '', @OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, @@SQL_QUOTE_SHOW_CREATE := 1 */
                   58 Query     USE `test`
                   58 Query     SHOW CREATE TABLE `test`.`zs`
                   58 Query     /*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, @@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */
                   58 Query     CREATE TABLE `test`.`_zs_new` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
                   58 Query     ALTER TABLE `test`.`_zs_new` add uid int
                   58 Query     /*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, @@SQL_MODE := '', @OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, @@SQL_QUOTE_SHOW_CREATE := 1 */
                   58 Query     USE `test`
                   58 Query     SHOW CREATE TABLE `test`.`_zs_new`
                   58 Query     /*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, @@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */

2.然后创建after触发器,使原数据表(zs)的insert、update、delete操作内容能传递到_zs_new数据表:

58 Query     CREATE TRIGGER `pt_osc_test_zs_del` AFTER DELETE ON `test`.`zs` FOR EACH ROW DELETE IGNORE FROM `test`.`_zs_new` WHERE `test`.`_zs_new`.`id` <=> OLD.`id`
                   58 Query     CREATE TRIGGER `pt_osc_test_zs_upd` AFTER UPDATE ON `test`.`zs` FOR EACH ROW REPLACE INTO `test`.`_zs_new` (`id`, `name`) VALUES (NEW.`id`, NEW.`name`)
                   58 Query     CREATE TRIGGER `pt_osc_test_zs_ins` AFTER INSERT ON `test`.`zs` FOR EACH ROW REPLACE INTO `test`.`_zs_new` (`id`, `name`) VALUES (NEW.`id`, NEW.`name`)

3.pt-online-schema-change读取原数据表中的记录,所读条数由chunk-size选项确定,将读取的记录复制到_zs_new数据表。

58 Query     EXPLAIN SELECT * FROM `test`.`zs` WHERE 1=1
                   58 Query     EXPLAIN SELECT `id`, `name` FROM `test`.`zs` LOCK IN SHARE MODE /*explain pt-online-schema-change 13294 copy table*/
                   58 Query     INSERT LOW_PRIORITY IGNORE INTO `test`.`_zs_new` (`id`, `name`) SELECT `id`, `name` FROM `test`.`zs` LOCK IN SHARE MODE /*pt-online-schema-change 13294 copy table*/

4.用户对原zs数据表执行的DML都会通过触发器自动反映到_zs_new数据表。pt-online-schema-change复制完所有记录后,使用rename将zs表更名为_zs_old,将_zs_new表名修改为zs。rename命令会将多个数据表的更名操作作为一个事物进行处理,所以更名过程中用户的查询不会失败。

58 Query     SHOW GLOBAL STATUS LIKE 'threads_running'
                   58 Query     ANALYZE TABLE `test`.`_zs_new` /* pt-online-schema-change */
                   58 Query     RENAME TABLE `test`.`zs` TO `test`.`_zs_old`, `test`.`_zs_new` TO `test`.`zs`
                   58 Query     DROP TRIGGER IF EXISTS `test`.`pt_osc_test_zs_del`
                   58 Query     DROP TRIGGER IF EXISTS `test`.`pt_osc_test_zs_upd`
                   58 Query     DROP TRIGGER IF EXISTS `test`.`pt_osc_test_zs_ins`
                   58 Query     SHOW TABLES FROM `test` LIKE '\_zs\_new'

5.使用pt-online-schema-change应注意

  (1)重复触发器:如果原数据表已经存在AFTER触发器,将无法使用pt-online-schema-change。

  (2)死锁:假设zs数据表的id列有唯一索引(unique index),pt-online-schema-change会使用主键,以内存为单位分割记录,然后将所选范围内的记录复制到_zs_new数据表。这一过程中对_zs_new数据表的主键加排它锁后,为了进行重复检查,还要对id列唯一索引加锁。用户修改的内容(insert、delete、update)也通过触发器应用到_zs_new数据表。但是通过触发器到来的查询会先对id列中创建的唯一索引加排它锁,然后试图再次向主键加锁时,会与pt-online-schema-change进程的以内存块为单位的复制作业产生死锁。

原文地址:https://www.cnblogs.com/xxmysql/p/5729461.html