pt-online-schema-change在对表进行表结构变更时,会创建三个触发器。

如下文测试案例中的t2表,表结构如下:

mysql> show create table t2\G
*************************** 1. row ***************************Table: t2
Create Table: CREATE TABLE `t2` (`id` int(11) NOT NULL AUTO_INCREMENT,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.07 sec)

只有一个自增列字段id。

创建的触发器如下:

CREATE TRIGGER `pt_osc_test_t2_del` AFTER DELETE ON `test`.`t2` FOR EACH ROW DELETE IGNORE FROM `test`.`__t2_new` WHERE `test`.`__t2_new`.`id` <=> OLD.`id`CREATE TRIGGER `pt_osc_test_t2_upd` AFTER UPDATE ON `test`.`t2` FOR EACH ROW REPLACE INTO `test`.`__t2_new` (`id`) VALUES (NEW.`id`)
CREATE TRIGGER `pt_osc_test_t2_ins` AFTER INSERT ON `test`.`t2` FOR EACH ROW REPLACE INTO `test`.`__t2_new` (`id`) VALUES (NEW.`id`)

DELETE触发器和INSERT触发器逻辑上没有任何问题。

但对于UPDATE触发器来说,如果某条记录已经拷贝到中间表中,此时,有针对该记录的UPDATE操作,且修改的是主键,此时,针对中间表触发的“REPLACE INTO `test`.`__t2_new` (`id`) VALUES (NEW.`id`)”操作只会插入一条新的记录,而不会删除原来的记录。

下面重现该场景

创建触发器构造测试数据

delimiter //
create procedure p1()
begindeclare v1 int default 1;set autocommit=0;while v1 <=10000000 doinsert into test.t2(id) values(null);set v1=v1+1;if v1%1000 =0 thencommit;end if;end while;
end //
delimiter ;
call p1;

此时,会生成1千万的数据

mysql> select count(*),min(id),max(id) from t2;
+----------+---------+----------+
| count(*) | min(id) | max(id)  |
+----------+---------+----------+
| 10000000 |       1 | 10000000 |
+----------+---------+----------+
1 row in set (4.29 sec)

利用pt-online-schema-change对t2表添加一列

# pt-online-schema-change --execute --alter "ADD COLUMN c1 DATETIME" --print D=test,t=t2

No slaves found.  See --recursion-method if host localhost.localdomain has slaves.
Not checking slave lag because no slaves were found and --check-slave-lag was not specified.
Operation, tries, wait:analyze_table, 10, 1copy_rows, 10, 0.25create_triggers, 10, 1drop_triggers, 10, 1swap_tables, 10, 1update_foreign_keys, 10, 1
Altering `test`.`t2`...
Creating new table...
CREATE TABLE `test`.`___t2_new` (`id` int(11) NOT NULL AUTO_INCREMENT,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10000001 DEFAULT CHARSET=utf8
Created new table test.___t2_new OK.
Altering new table...
ALTER TABLE `test`.`___t2_new` ADD COLUMN c1 DATETIME
Altered `test`.`___t2_new` OK.
2016-10-23T20:24:13 Creating triggers...
CREATE TRIGGER `pt_osc_test_t2_del` AFTER DELETE ON `test`.`t2` FOR EACH ROW DELETE IGNORE FROM `test`.`___t2_new` WHERE `test`.`___t
2_new`.`id` <=> OLD.`id`CREATE TRIGGER `pt_osc_test_t2_upd` AFTER UPDATE ON `test`.`t2` FOR EACH ROW REPLACE INTO `test`.`___t2_new` (`id`) VALUES (NEW.`id`)
CREATE TRIGGER `pt_osc_test_t2_ins` AFTER INSERT ON `test`.`t2` FOR EACH ROW REPLACE INTO `test`.`___t2_new` (`id`) VALUES (NEW.`id`)
2016-10-23T20:24:13 Created triggers OK.
2016-10-23T20:24:13 Copying approximately 9429750 rows...
INSERT LOW_PRIORITY IGNORE INTO `test`.`___t2_new` (`id`) SELECT `id` FROM `test`.`t2` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= ?)) AND((`id` <= ?)) LOCK IN SHARE MODE /*pt-online-schema-change 2456 copy nibble*/SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `test`.`t2` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= ?)) ORDER BY `id` LIMIT ?, 2 /*next chun
k boundary*/Copying `test`.`t2`:  29% 01:12 remain
Copying `test`.`t2`:  52% 00:54 remain
Copying `test`.`t2`:  76% 00:27 remain
2016-10-23T20:26:22 Copied rows OK.
2016-10-23T20:26:22 Analyzing new table...
2016-10-23T20:26:23 Swapping tables...
RENAME TABLE `test`.`t2` TO `test`.`_t2_old`, `test`.`___t2_new` TO `test`.`t2`
2016-10-23T20:26:24 Swapped original and new tables OK.
2016-10-23T20:26:24 Dropping old table...
DROP TABLE IF EXISTS `test`.`_t2_old`
2016-10-23T20:26:24 Dropped old table `test`.`_t2_old` OK.
2016-10-23T20:26:24 Dropping triggers...
DROP TRIGGER IF EXISTS `test`.`pt_osc_test_t2_del`;
DROP TRIGGER IF EXISTS `test`.`pt_osc_test_t2_upd`;
DROP TRIGGER IF EXISTS `test`.`pt_osc_test_t2_ins`;
2016-10-23T20:26:24 Dropped triggers OK.
Successfully altered `test`.`t2`.

当输出到上述红色信息时,打开另外一个终端窗口,执行如下命令

 mysql -e 'update test.t2 set id=-1 where id=1'mysql -e 'update test.t2 set id=-2 where id=2'mysql -e 'update test.t2 set id=-3 where id=3'mysql -e 'update test.t2 set id=-4 where id=4'mysql -e 'update test.t2 set id=-5 where id=5'mysql -e 'update test.t2 set id=-6 where id=6'mysql -e 'update test.t2 set id=-7 where id=7'mysql -e 'update test.t2 set id=-8 where id=8'mysql -e 'update test.t2 set id=-9 where id=9'mysql -e 'update test.t2 set id=-10 where id=10'

查看t2表修改完表结构后的数据情况

mysql> select count(*),min(id),max(id) from t2;
+----------+---------+----------+
| count(*) | min(id) | max(id)  |
+----------+---------+----------+
| 10000010 |     -10 | 10000000 |
+----------+---------+----------+
1 row in set (3.00 sec)mysql> select * from t2 order by id limit 20;
+-----+------+
| id  | c1   |
+-----+------+
| -10 | NULL |
|  -9 | NULL |
|  -8 | NULL |
|  -7 | NULL |
|  -6 | NULL |
|  -5 | NULL |
|  -4 | NULL |
|  -3 | NULL |
|  -2 | NULL |
|  -1 | NULL |
|   1 | NULL |
|   2 | NULL |
|   3 | NULL |
|   4 | NULL |
|   5 | NULL |
|   6 | NULL |
|   7 | NULL |
|   8 | NULL |
|   9 | NULL |
|  10 | NULL |
+-----+------+
20 rows in set (0.08 sec)

可见,在执行pt-online-schema-change命令的过程中,针对原表执行的update操作并没有理所当然的反应到中间表上。

总结

1. 上述测试使用的pt-online-schema-change是2.2.19版本。

2. 欲进行表结构变更的表中必须存在主键或者唯一索引。

体现在以下方面:

1> 针对DELETE触发器

CREATE TRIGGER `pt_osc_test_t2_del` AFTER DELETE ON `test`.`t2` FOR EACH ROW DELETE IGNORE FROM `test`.`_t2_new` WHERE `test`.`_t2_new`.`id` <=> OLD.`id`

DELETE触发器是基于主键或者唯一索引进行删除的。如果id是普通索引,则原表中可能只有一行记录的删除(譬如delete from t where id=1 and name='victor'),导致中间表中所有id为1的记录的删除。

2> 针对UPDATE触发器

如果原表中不存在主键或者唯一索引,则replace操作会直接插入,而不会进行替换。

mysql> create table t3(id int,name varchar(10));
Query OK, 0 rows affected (0.08 sec)mysql> insert into t3 values(1,'a');
Query OK, 1 row affected (0.05 sec)mysql> replace into t3 values(1,'b');
Query OK, 1 row affected (0.06 sec)mysql> select * from t3;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    1 | b    |
+------+------+
2 rows in set (0.00 sec)mysql> alter table t3 modify id int primary key;
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
mysql> delete from t3 where id=1 and name='b';
Query OK, 1 row affected (0.07 sec)mysql> alter table t3 modify id int primary key;
Query OK, 0 rows affected (0.24 sec)
Records: 0  Duplicates: 0  Warnings: 0mysql> select * from t3;
+----+------+
| id | name |
+----+------+
|  1 | a    |
+----+------+
1 row in set (0.00 sec)mysql> replace into t3 values(1,'b');
Query OK, 2 rows affected (0.01 sec)mysql> select * from t3;
+----+------+
| id | name |
+----+------+
|  1 | b    |
+----+------+
1 row in set (0.01 sec)

3. 即便欲进行表结构变更的表中存在主键或者唯一索引,如果在利用pt-online-schema-change进行online ddl过程中,有针对主键的更新操作,则会导致记录的新增。这点需引起注意。

pt-online-schema-change中update触发器的bug相关推荐

  1. SQL server触发器中 update insert delete 分别给写个例子被。

    SQL server触发器中 update insert delete 分别给写个例子以及解释下例子的作用和意思被, 万分感谢!!!! 主要想知道下各个语句的书写规范. INSERT: 表1 (ID, ...

  2. mysql schema 保存数据_在MySQL中,所有触发器的定义都保存在information_schema数据库下的()表中。_学小易找答案...

    [单选题]如何将英制 的零件转为公制的零件 ( ). [判断题]连续选择边线创建倒角时,不能单独修改某一边线的倒角大小 [判断题]创建筋特征时截面必须是闭和的 [填空题]Hibernate 的会话接口 ...

  3. mysql 触发器 sql日志_sql update 触发器 可获得被update的行的信息

    SQL Server 2005 学习笔记之触发器简介[转] 触发器实际上就是一种特殊类型的存储过程,其特殊性表现在:它是在执行某些特定的T-SQL语句时自动的. 11.1 触发器简介 触发器实际上就是 ...

  4. oracle中创建触发器

    从csdn上面看到一个如何创建触发器的问题,感觉自己很有必要保存学习,特写下来: 条件: 现有A.B两张表 A: 工号 姓名 密码 性别 年龄 ... B: 工号 姓名 密码 当对A表中的" ...

  5. AppBoxFuture(四). 随需而变-Online Schema Change

      需求变更是信息化过程中的家常便饭,而在变更过程中如何尽可能小的影响在线业务是比较头疼的事情.举个车联网监控的例子:原终端设备上传车辆的经纬度数据,新的终端设备支持同时上传速度数据,而旧的车辆状态表 ...

  6. sql server update触发器_SQL Server 触发器

    T-SQL 触发器 触发器分为 BEFORE触发器*(SQL Server不支持,Oracle支持)在事件发生时触发. AFTER触发器是 SQLServer生成的最初用于自动相应数据修改的机制.在 ...

  7. java触发器如何创建表_在java 中执行触发器代码、创表语句

    由于程序的需要,在SQLServer 中创建触发器及建表,碰到了在java 代码中执行创建触发器及表. /**建立中间表*/ public static final String createMidd ...

  8. 详解SQL中的触发器

    ● 原因 ● 触发器 ○ 简介 ○ 分类 ○ INSERTED和DELETED ○ 优缺点 ● 语法 ○ 建立触发器 ○ 删除触发器 ○ 修改触发器 ○ 开启和禁用 ○ 提醒和保护 ● 示例 原因 今 ...

  9. MySQL错误代码:MySQL Workbench中UPDATE期间的1175错误代码

    本文翻译自:MySQL error code: 1175 during UPDATE in MySQL Workbench I'm trying to update the column visite ...

最新文章

  1. 在ubuntu16.04中安装apache2+modsecurity以及自定义WAF规则详解
  2. SAP Fiori + Vue = ?
  3. flyway java使用,如何使用flyway创建数据库?
  4. sqlite+php+函数大全,PHP SQLite SQLite 函数_编程学问网
  5. pyecharts第五节、关系图
  6. 每日程序C语言46-函数之间的调用
  7. 更新Docker中的Jenkins版本
  8. 剑指offer-JZ30 包含min函数的栈(C++,附自己的分析)
  9. python idle 常规命令_Python的3种运行方式:命令行窗口、Python解释器、IDLE的实现
  10. spark streaming限制吞吐
  11. pwn环境搭建_[原创]CTF_Pwn环境搭建
  12. 反序列化时出现“base-64 字符数组的无效长度”错误提示的解决
  13. 通过矩阵操作实现点的2D线性变换(几何变换、仿射变换)
  14. 拼多多36W+的后端面经
  15. 木鱼网址缩短服务 短域名生成网站源码
  16. xshell最多支持4个_3分钟苹果发布会:iPhone12支持5G、3个尺寸4种型号
  17. php正则怎么用,php正则及常用正则函数怎么用
  18. SwiftUI - Text
  19. python版本和Matlab版本对应的关系,python调用matlab
  20. asp.net中GridView排序的手动实现

热门文章

  1. 科大讯飞语音助手Lite智能鼠标电脑版安装不成功为什么?怎么办?
  2. Day2-springmvc初解
  3. python从入门到实践学习笔记_Python编程从入门到实践:学习笔记1(第二章)
  4. android 时钟进度条,CSS3时钟式进度条
  5. oracle date类型,向Oracle中插入date数据类型
  6. c语言报告程序分析报告,2012C语言程序分析报告.doc
  7. python 冷门_csvkit---python一个牛逼到不行的csv处理库
  8. 使用录制宏制作工资条
  9. idea远程debug调试阿里云ECS
  10. 享元模式(FlyWeight)