pt-online-schema-change在线DDL工具可以做到DDL操作不锁表,不影响线上操作。对于线上超过100W的大表,一般情况下都用这个工具做DDL,最重要的考虑点还是“不影响线上操作
pt-online-schema-change内部操作流程
1)创新新的临时表,临时表为DDL后的目标表结构
2)在原表上创建增删改三个触发器,当原表有数据DML操作时,通过触发器同步数据到新的临时表
3)把原表的数据分批倒入到新的临时表
4)新表,老表做表名称互换操作
5)删除修改后表的触发器
 
删除失败验证步骤
1)创建表,ID自增,作为主键,10条记录
mysql> CREATE TABLE `zxy_test` ( -> `id` bigint(20) NOT NULL AUTO_INCREMENT, -> `FUSERID` int(11) DEFAULT NULL, -> PRIMARY KEY (`id`), -> KEY `idx` (`FUSERID`) -> ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4; Query OK, 0 rows affected (0.00 sec) mysql> insert into zxy_test values(1,1),(2,2),(3,3),(4,4); Query OK, 4 rows affected (0.00 sec) Records: 4 Duplicates: 0 Warnings: 0

2)把这个表的主键从ID改成FUSERID,用pt这个工具,在改的过程中,对原表做增删改的操作。表记录数很小,不做真实的ddl全部操作,print出pt操作过程,人为的把DDL时间延长,以求有足够的时间做中间操作。模拟pt工具,创建new表,创建触发器

pt执行的命令是:pt-online-schema-change --user=root --password='XXXX' --host=10.3.172.112 D=test,t=zxy_test  --alter "DROP ID,ADD PRIMARY KEY(FUSERID);" --charset=utf8 --no-check-replication-filters  --execute
mysql> CREATE TABLE `test`.`_zxy_test_new` (
-> `id` bigint(20) NOT NULL AUTO_INCREMENT,
-> `FUSERID` int(11) DEFAULT NULL,
-> PRIMARY KEY (`id`),
-> KEY `idx` (`FUSERID`)
-> ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected (0.00 sec) mysql> ALTER TABLE `test`.`_zxy_test_new` DROP ID,ADD PRIMARY KEY(FUSERID);
Query OK, 0 rows affected (1.30 sec)
Records: 0 Duplicates: 0 Warnings: 0 mysql> CREATE TRIGGER `pt_osc_test_zxy_test_del` AFTER DELETE ON `test`.`zxy_test` FOR EACH ROW DELETE IGNORE FROM `test`.`_zxy_test_new` WHERE `test`.`_zxy_test_new`.`id` <=> OLD.`id`;
Query OK, 0 rows affected (0.00 sec) mysql> CREATE TRIGGER `pt_osc_test_zxy_test_upd` AFTER UPDATE ON `test`.`zxy_test` FOR EACH ROW REPLACE INTO `test`.`_zxy_test_new` (`fuserid`) VALUES (NEW.`fuserid`);
Query OK, 0 rows affected (0.01 sec) mysql> CREATE TRIGGER `pt_osc_test_zxy_test_ins` AFTER INSERT ON `test`.`zxy_test` FOR EACH ROW REPLACE INTO `test`.`_zxy_test_new` (`fuserid`) VALUES (NEW.`fuserid`);
Query OK, 0 rows affected (0.00 sec) mysql>

3)开始对原表的数据做增删改操作,操作记录会通过触发器同步到新表

新增的记录:新增没有问题
mysql> select * from zxy_test;
+----+---------+
| id | FUSERID |
+----+---------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
+----+---------+
4 rows in set (0.00 sec) mysql> select * from _zxy_test_new;
Empty set (0.00 sec) mysql> insert into zxy_test values(5,5);
Query OK, 1 row affected (0.00 sec) mysql> select * from zxy_test;
+----+---------+
| id | FUSERID |
+----+---------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
+----+---------+
5 rows in set (0.00 sec) mysql> select * from _zxy_test_new;
+---------+
| FUSERID |
+---------+
| 5 |
+---------+
1 row in set (0.00 sec)

修改记录:修改没有问题

mysql> select * from zxy_test;
+----+---------+
| id | FUSERID |
+----+---------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
+----+---------+
5 rows in set (0.00 sec) mysql> select * from _zxy_test_new;
+---------+
| FUSERID |
+---------+
| 5 |
+---------+
1 row in set (0.00 sec) mysql> update zxy_test set fuserid=10 where id=1;
Query OK, 1 row affected (0.02 sec)
Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from zxy_test;
+----+---------+
| id | FUSERID |
+----+---------+
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 1 | 10 |
+----+---------+
5 rows in set (0.00 sec) mysql> select * from _zxy_test_new;
+---------+
| FUSERID |
+---------+
| 5 |
| 10 |
+---------+
2 rows in set (0.00 sec)

删除记录,删除记录失败,原表数据不变,新表数据不变

mysql> select * from zxy_test;
+----+---------+
| id | FUSERID |
+----+---------+
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 1 | 10 |
+----+---------+
5 rows in set (0.00 sec) mysql> select * from _zxy_test_new;
+---------+
| FUSERID |
+---------+
| 5 |
| 10 |
+---------+
2 rows in set (0.00 sec) mysql> delete from zxy_test where fuserid=2;
ERROR 1054 (42S22): Unknown column 'test._zxy_test_new.id' in 'where clause'
mysql> select * from zxy_test;
+----+---------+
| id | FUSERID |
+----+---------+
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 1 | 10 |
+----+---------+
5 rows in set (0.00 sec) mysql> select * from _zxy_test_new;
+---------+
| FUSERID |
+---------+
| 5 |
| 10 |
+---------+
2 rows in set (0.00 sec)

看报错信息“ERROR 1054 (42S22): Unknown column 'test._zxy_test_new.id' in 'where clause'”,提示test._zxy_test_new.id 不存在,修改后的表是没有id字段的,这个错误是由delete触发器报出。delete触发器命令:CREATE TRIGGER `pt_osc_test_zxy_test_del` AFTER DELETE ON `test`.`zxy_test` FOR EACH ROW DELETE IGNORE FROM `test`.`_zxy_test_new` WHERE `test`.`_zxy_test_new`.`id` <=> OLD.`id`; 在删除原表记录的时候,通过主键去定位被触发的记录,在new表里删除,这样做的目的是保证删除触发删除的记录在两个表里绝对是一致的。

最后贴出pt执行时,在MYSQL里面执行的全部SQL命令,关键信息蓝色加粗,完全对应文章开篇的步骤
13134 Query SHOW TABLES FROM `test` LIKE 'zxy\_test'
13134 Query SHOW TRIGGERS FROM `test` LIKE 'zxy\_test'
13134 Query /*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, @@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), @OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, @@SQL_QUOTE_SHOW_CREATE := 1 */
13134 Query USE `test`
13134 Query SHOW CREATE TABLE `test`.`zxy_test`
13134 Query /*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, @@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */
13134 Query EXPLAIN SELECT * FROM `test`.`zxy_test` WHERE 1=1
13134 Query SHOW INDEXES FROM `test`.`zxy_test` WHERE Key_name = 'idx'
13134 Query SELECT table_schema, table_name FROM information_schema.key_column_usage WHERE constraint_schema='test' AND referenced_table_name='zxy_test'
151125 15:36:59 13134 Query /*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, @@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), @OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, @@SQL_QUOTE_SHOW_CREATE := 1 */
13134 Query USE `test`
13134 Query SHOW CREATE TABLE `test`.`zxy_test`
13134 Query /*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, @@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */
13134 Query CREATE TABLE `test`.`_zxy_test_new` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`FUSERID` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx` (`FUSERID`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4
13134 Query ALTER TABLE `test`.`_zxy_test_new` DROP ID,ADD PRIMARY KEY(FUSERID)
151125 15:37:01 13134 Query /*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, @@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), @OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, @@SQL_QUOTE_SHOW_CREATE := 1 */
13134 Query USE `test`
13134 Query SHOW CREATE TABLE `test`.`_zxy_test_new`
13134 Query /*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, @@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */
13134 Query CREATE TRIGGER `pt_osc_test_zxy_test_del` AFTER DELETE ON `test`.`zxy_test` FOR EACH ROW DELETE IGNORE FROM `test`.`_zxy_test_new` WHERE `test`.`_zxy_test_new`.`id` <=> OLD.`id`
13134 Query CREATE TRIGGER `pt_osc_test_zxy_test_upd` AFTER UPDATE ON `test`.`zxy_test` FOR EACH ROW REPLACE INTO `test`.`_zxy_test_new` (`fuserid`) VALUES (NEW.`fuserid`)
13134 Query CREATE TRIGGER `pt_osc_test_zxy_test_ins` AFTER INSERT ON `test`.`zxy_test` FOR EACH ROW REPLACE INTO `test`.`_zxy_test_new` (`fuserid`) VALUES (NEW.`fuserid`)
13134 Query EXPLAIN SELECT * FROM `test`.`zxy_test` WHERE 1=1
13134 Query SHOW INDEXES FROM `test`.`zxy_test` WHERE Key_name = 'idx'
13134 Query INSERT LOW_PRIORITY IGNORE INTO `test`.`_zxy_test_new` (`fuserid`) SELECT `fuserid` FROM `test`.`zxy_test` /*pt-online-schema-change 27995 copy table*/
13134 Query SHOW WARNINGS
13134 Query SHOW GLOBAL STATUS LIKE 'Threads_running'
13134 Query RENAME TABLE `test`.`zxy_test` TO `test`.`_zxy_test_old`, `test`.`_zxy_test_new` TO `test`.`zxy_test`
13134 Query DROP TABLE IF EXISTS `test`.`_zxy_test_old`
13134 Query DROP TRIGGER IF EXISTS `test`.`pt_osc_test_zxy_test_del`
13134 Query DROP TRIGGER IF EXISTS `test`.`pt_osc_test_zxy_test_upd`
13134 Query DROP TRIGGER IF EXISTS `test`.`pt_osc_test_zxy_test_ins`
13134 Query SHOW TABLES FROM `test` LIKE '\_zxy\_test\_new'

结论:

用PT工具做主键删除的DDL,在DDL执行的过程中,如果有对原表的增删改操作,增改操作正常运行,删除操作会失败。

 

pt-online-schema-change 修改主键导致数据删除失败的问题调查的更多相关文章

  1. 修改主键id为自增

    详见:sqlserver修改主键为自增 先删除id字段, 执行下面sql即可: alter table sms_rec add id int IDENTITY (1,1) PRIMARY KEY

  2. 创建和修改主键 (SQL)

    添加主键, ALTER TABLE [表名:OrderInfo] Add PRIMARY KEY ([列名:ProductID, UserID...])  多个列则是组合主键 删除主键, ALTER ...

  3. Oracle修改主键约束

    项目需求,有张表,原有三个联合主键,现在需要再加一个字段进去,而恰恰这个字段可以为空的.去数据库捞了一把,还好数据都不为空: SQL> select count(*) from t_wlf_re ...

  4. SQL 修改主键约束

    原文:SQL 修改主键约束 今天在学习数据库的时候遇到一个关于如何修改主键约束的问题,抄录下来以供备用. --修改主键约束用SQL --获取主键约束名字 declare @csname varchar ...

  5. SQL查找数据库中所有没有主键的数据表脚本

    --SQL查找数据库中所有没有主键的数据表脚本 --运行脚本后在消息中可能会显示下面现象中的一种:--(1)数据库中所有数据表都有主键(则证明所有数据表都有主键)--(2)当前数据表[数据表名]没有主 ...

  6. MySQL中因为unique key 非空唯一索引存在导致修改主键失败案例

    研发在早期的设计中,由于设计方面的问题,导致在设计表结构的时候,有个表有非空唯一索引而没有主键 在InnoDB存储引擎中,如果没有主键的情况下,有非空唯一索引的话,非空唯一索引即为主键. 那么这就会有 ...

  7. sqlserver修改主键为自增

    使用PowerDesigner创建一张表, 拷贝建表语句发现ID不是自增的, 以下是修改语句: ALTER TABLE USER_JOB_EXE_REC DROP COLUMN id; , ); 注: ...

  8. mysql 创建主键,修改主键

    //添加一个字段pid并且设置为主键(auto_increment)自增(auto_increment),不可为null,类型为int unsigned alter table table1 add ...

  9. mysql修改主键

    先删除所有主键 alter table tableName drop primary key; 然后添加主键 alter table tableName primary key(id);//如果是联合 ...

随机推荐

  1. Ajax学习重点总结

    1.什么是AJAX AJAX=Asynchronous JavaScript and XML(异步的JavaScript和XML). AJAX是在不重新加载整个页面的情况下,后台与服务器交换数据并更新 ...

  2. 错误:The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path

    我们在利用Eclipse进行Java web开发时,可能会出现这样的错误:The superclass javax.servlet.http.HttpServlet was not found on ...

  3. gnuplot安装的小问题

    今天在学习NS2的过程中接触到了awk和gnuplot来分析延迟,丢包等情况. gnuplot是一款非常精巧的绘图工具,使用方法也很简单,功能却很强大. 安装还是通过终端: sudo apt-get ...

  4. 关于几种编程过程中的注释(TODO、FIXME、XXX等)

    最近看别人写的代码,注意到很多规范的代码的注释写的都特别好.只是不太明白TODO.FIXME这些事什么意思.查阅资料,看到一篇博客,遂转载而来,以供今后查阅. (转载地址http://www.cnbl ...

  5. python sproto支持64位有符号整数

    小伙伴需要64位整数做物品的id,之前python sproto的判断有问题,写篇日志记录一下. 之前有问题的代码是这样的: if (!PyInt_Check(data)) { PyErr_SetOb ...

  6. 利用jQuery和CSS实现环形进度条

    实现原理 原理非常的简单,在这个方案中,最主要使用了CSS3的transform中的rotate和CSS3的clip两个属性.用他们来实现半圆和旋转效果. 半环的实现 先来看其结构. HTML < ...

  7. Lua Coroutine详解

    协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈,局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西.线程与协同程序的主要区别在于,一个具有多线程的程序可以同时运行几个线程 ...

  8. 使用CocoaPod导入Swift第三方库报错

    在使用cocoapod导入swift第三方时出现这样的错误: [!] Pods written in Swift can only be integrated as frameworks; add ` ...

  9. 转自一个CG大神的文章

    <如何学好游戏3D引擎编程>此篇文章献给那些为了游戏编程不怕困难的热血青年,它的神秘要我永远不间断的去挑战自我,超越自我,这样才能攀登到游戏技术的最高峰           ——阿哲VS自 ...

  10. 【python】jiraAPI使用教程 自动创建jira问题单并置状态为OPEN

    环境依赖 : python库 redis jira  安装命令:pip install redis pip install jira redis服务安装命令: $sudo apt-get update ...