1 OSC介绍

在我们的数据库操作中,更改表结构是一个常见的操作,而当我们的表数据量非常大时,我们更改表结构的时间是非
常的长,并且在跟改期间,会生成一个互斥锁,阻塞对整个表的所有操作,这样,对于我们线上数据来说是无法容忍
的,以往的做法中,为了不影响线上业务,我们一般采用:先在线下从库更改表结构,然后替换线上从库,这样一台
台的修改,最后做一下主库切换,这个过程会耗费很长时间,并且在做主库切换时,风险也非常的大,OSC(Online
Schema Change)大多都是利用了触发器的原理,实现了在线更改表结构的同时,避免了锁表,同时还允许其他的dml操
作,目前已经有多种工具实现了 OSC 下面就几种常见的的工具。

2 MySQL5.6 OnlineDDL

MySQL5.6 Online DDL可以做到DDL\DML\SELECT同时进行

示例

alter table test add name varchar(10),ALGORITHM=INPLACE ,LOCK=NONE;

#Locking Options for Online DDL
LOCK=DEFAULT
LOCK=NONE
LOCK=SHARED
LOCK=EXCLUSIVE #Performance of In-Place versus Table-Copying DDL Operations
ALGORITHM=DEFAULT
ALGORITHM=INPLACE
ALGORITHM=COPY

实现细节

#Prepare阶段
1.创建临时frm文件
2.持有EXCLUSIVE-MDL锁,禁止读写
3.根据ALTER类型,确定执行方式(copy,online-rebuild,online-norebuild)
4.更新数据字典的内存对象
5.分配row_log对象记录增量
6.生成临时ibd文件 #ddl执行阶段
1.降级EXCLUSIVE-MDL锁,允许读写
2.扫描原表的聚簇索引每条记录
3.遍历新表的聚簇索引和二级索引,逐一处理
4.根据记录构造对应的索引项
5.将构造索引项插入sort_buffer块
6.将sort_buffer块插入新的索引
7.处理ddl执行过程中产生的增量(仅rebuild类型需要) #commit阶段
1.升级到EXCLUSIVE-MDL锁,禁止读写
2.应用最后row_log中产的日志
3.更新innodb的数据字典表
4.提交事务(刷事务的redo日志)
5.修改统计信息
6.rename临时idb文件,frm文件
7.变更完成

从上面可以看到 在开始 和 结束阶段 还是锁表了 只是缩短了锁表的时间

以加索引为例,介绍 copy方式跟inplace方式的实现流程

#copy方式

1.新建带索引(主键索引)的临时表

2.锁原表,禁止DML,允许查询

3.将原表数据拷贝到临时表

4.禁止读写,进行rename,升级字典锁

5.完成创建索引操作

#inplace方式
1.创建索引(二级索引)数据字典
2.加共享表锁,禁止DML,允许查询
3.读取聚簇索引,构造新的索引项,排序并插入新索引
4.等待打开当前表的所有只读事务提交
5.创建索引结束

3 Percona公司的pt-online-schema-change

示例

pt-online-schema-change h=*,u=* p=**,P=* ,D=enk,t=my1 --alter "add is_sign_1 int(11) unsigned NOT NULL DEFAULT '0'" --drop-old-table [--sleep 10] --print --executeD=lots,t=t_o_tr

实现细节

1. 新建tmp_table,表结构同原表
CREATE TABLE `$db`.`$tmp_tbl` LIKE `$db`.`$tbl`" 2. 在tmp_table上更改表结构为需要的表结构 3. 在原表上建立三个触发器,如下:
#delete 触发器
CREATE TRIGGER mk_osc_del AFTER DELETE ON $table " "FOR EACH ROW "
"DELETE IGNORE FROM $new_table ""WHERE $new_table.$chunk_column = OLD.$chunk_column";
#insert 触发器
CREATE TRIGGER mk_osc_ins AFTER INSERT ON $table " "FOR EACH ROW "
"REPLACE INTO $new_table ($columns) " "VALUES($new_values)";
#update 触发器
CREATE TRIGGER mk_osc_upd AFTER UPDATE ON $table " "FOR EACH ROW "
"REPLACE INTO $new_table ($columns) " "VALUES ($new_values)"; #我们可以看到这三个触发器分别对应于INSERT、UPDATE、DELETE三种操作,
mk_osc_del,DELETE操作,我们注意到DELETE IGNORE,当新有数据时,我们才进行操作,也就是说,当在后续导入过程中,如果删除
的这个数据还未导入到新表,那么我们可以不在新表执行操作,因为在以后的导入过程中,原表中改行数据已经被删除,已经没有数据,那
么他也就不会导入到新表中; mk_osc_ins,INSERT操作,所有的INSERT INTO全部转换为REPLACE INTO,为了确保数据的一致性,当有新数据插入到原表时,如果
触发器还未把原表数据未同步到新表,这条数据已经被导入到新表了,那么我们就可以利用replace into进行覆盖,这样数据也是一致的。 mk_osc_upd UPDATE操作,所有的UPDATE也转换为REPLACE INTO,因为当跟新的数据的行还未同步到新表时,新表是不存在这条记录
的,那么我们就只能插入该条数据,如果已经同步到新表了,那么也可以进行覆盖插入,所有数据与原表也是一致的; #我们也能看出上述的精髓也就这这几条replace into操作,正是因为这几条replace into才能保证数据的一致性 4. 拷贝原表数据到临时表中,在脚本中使用如下语句
INSERT IGNORE INTO $to_table ($columns) " "SELECT $columns FROM $from_table " "WHERE ($chunks->[$chunkno])",
我们能看到他是通过一些查询(基本为主键、唯一键值)分批把数据导入到新的表中,在导入前,我们能通过参数--chunk-size对每次
导入行数进行控制,已减少对原表的锁定时间,并且在导入时,我们能通过—sleep参数控制,在每个chunk导入后与下一次chunk导入开
始前sleep一会,sleep时间越长,对于磁盘IO的冲击就越小 5. Rename 原表到old表中,在把临时表Rename为原表
RENAME TABLE `$db`.`$tmp_tbl` TO `$db`.`$tbl` ;
在rename过程,其实我们还是会导致写入读取堵塞的,所以从严格意思上说,我们的OSC也不是对线上环境没有一点影响,但由于
rename操作只是一个修改名字的过程,也只会修改一些表的信息,基本是瞬间结束,故对线上影响不太大 6. 清理以上过程中的不再使用的数据,如OLD表

以上即为整个Percona OSC的过程,我们看到精华部分就触发器那一块,不过还有很多细节我未介绍,如:外键、记录binlog(默认情况是不记录binlog的)等等

由于环境的复杂性,此工具还是有很多风险,如以下几个方面问题或者需要规避的一些问题:

1. 此工具不是原子操作,如果某一点失败,不仅仅会留下很多中间过程的垃圾文件,而这些文件很难完全清理,并且如果有这些文件存在,

那么就不能在次执行OSC操作;

2.在执行时,尽量避免有这个表的批量更新、锁表、优化表的操作,我们能想象的到,如果有锁表、优化表那么OSC是否还能正常执行?

3.如果存在主从结构,那么尽量在从库先执行,因为如果在主库执行完毕后在到从库执行,我们能想象,主库字段多同步到从库,会不会有问题呢?

4.必须是单一列的主键或者单一唯一键,这样我们在insert select *from分片时,是不是能更好的处理量呢?

5.不要有外键,尽管脚本经过严格测试,但是是否还有bug,也未知,表的外键是不是会带来更多的问题呢?

6.在执行之前,我们是不是要对磁盘容量进行评估呢?因为OSC会使用表的一倍以上空间。

**以上列到的,只是部分问题,我想如果需要在线进行实施,还需要经过严格的测试,但是它的实现为我们提供了一个很好的在线更改表结构 方法,我相信只要我们能很好的规避他的弊端,它会给我们带来很大的帮助;

**

PS:

使用 pt-osc 修改主键时注意:

原表上有个复合主键,现在要添加一个自增 id 作为主键,如何进行?

会涉及到以下修改动作:

 1.删除复合主键定义
2.添加新的自增主键 3.原复合主键字段,修改成唯一索引

需要将删除原主键、增加新主键和增加原主键为唯一键同时操作:

alter "DROP PRIMARY KEY,add column pk int auto_increment primary key,add unique key uk_id_k(id,k)

3.4 OAK Openark – kit

openark kit 提供一组小程序,用来帮助日常的 MySQL 维护任务,可代替繁杂的手工操作。

oak-apply-ri: apply referential integrity on two columns with parent-child relationship.
oak-block-account: block or release MySQL users accounts, disabling them or enabling them to login.
oak-chunk-update: Perform long, non-blocking UPDATE/DELETE operation in auto managed small chunks.
oak-kill-slow-queries: terminate long running queries.
oak-modify-charset: change the character set (and collation) of a textual column.
oak-online-alter-table: Perform a non-blocking ALTER TABLE operation.
oak-purge-master-logs: purge master logs, depending on the state of replicating slaves.
oak-security-audit: audit accounts, passwords, privileges and other security settings.
oak-show-limits: show AUTO_INCREMENT “free space”.
oak-show-replication-status: show how far behind are replicating slaves on a given master.

示例

 python oak-online-alter-table -u root --ask-pass -S /u01/mysql/my3306/run/mysql.sock -d replTestDB -t sbtest1 -g new_sbtest1 -a "add last_update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,add key last_update_time(last_update_time)" --sleep=300 --skip-delete-pass

实现细节

# 1.确认该表是否符合 oak-online-alter-table 的执行条件:
已有触发器? 检查触发器->备份触发器->删除触发器
SELECT TRIGGER_SCHEMA,TRIGGER_NAME,EVENT_OBJECT_SCHEMA,
EVENT_OBJECT_TABLE
FROM information_schema.TRIGGERS
WHERE event_object_schema = 'replTestDB'; Select * from information_schema.key_column_usage where
Referenced_table_schema='replTestDB' and
Referenced_table_name='sbtest1'; #2.执行 oak 命令,至于执行时间:
如果表有 1亿,大概要执行 12 个小时,就需要在一周业务量少的时候执行 cd /u01/tools/openark-kit-196/scripts/
python oak-online-alter-table -u root --ask-pass -S /u01/mysql/my3306/run/mysql.sock -d replTestDB -t sbtest1 -g new_sbtest1 -a "add last_update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,add key last_update_time(last_update_time)" --sleep=300 --skip-delete-pass #3.Online DDL 之后要进行数据一致性校验:如果 DDL 改变了表字段类型,可能导致表数据变化 #4.表切换
rename table sbtest1 to old_sbtest1,new_sbtest1 to sbtest1; #5. 删除触发器
drop trigger sbtest1_AI_oak;
drop trigger sbtest1_AU_oak;
drop trigger sbtest1_AD_oak; #6.删除表

MySQL OSC(在线更改表结构)原理的更多相关文章

  1. gh-ost 号称是不需要触发器(Triggerless)支持的在线更改表结构的工具

    https://segmentfault.com/a/1190000006158503?utm_source=tuicool&utm_medium=referral

  2. [linux][mysql] 命令更改表结构:添加、删除、修改字段、调整字段顺序

    原文出处:http://www.phpernote.com/MySQL/1120.html 查看表结构: desc tabl_name; show columns fromtable_name: 常用 ...

  3. (转)pt-online-schema-change在线修改表结构

    原文:http://www.ywnds.com/?p=4442 一.背景 MySQL大字段的DDL操作:加减字段.索引.修改字段属性等,在5.1之前都是非常耗时耗力的,特别是会对MySQL服务产生影响 ...

  4. mysql在线修改表结构大数据表的风险与解决办法归纳

    整理这篇文章的缘由: 互联网应用会频繁加功能,修改需求.那么表结构也会经常修改,加字段,加索引.在线直接在生产环境的表中修改表结构,对用户使用网站是有影响. 以前我一直为这个问题头痛.当然那个时候不需 ...

  5. 数据库遇到的问题——mysql在线修改表结构大数据表的风险与解决办法归纳

    互联网应用会频繁加功能,修改需求.那么表结构也会经常修改,加字段,加索引.在线直接在生产环境的表中修改表结构,对用户使用网站是有影响. 以前我一直为这个问题头痛.当然那个时候不需要我来考虑,虽然我们没 ...

  6. MySQL在创建相同表结构时as和like 使用的区别

    1.MySQL的复制相同表结构方法: 1)create table table_name as select * from table1 where 1=2 (或者limit  0): 2) crea ...

  7. 【工具篇】利用DBExportDoc V1.0 For MySQL自动生成数据库表结构文档

    对于DBA或开发来说,如何规范化你的数据库表结构文档是灰常之重要的一件事情.但是当你的库,你的表排山倒海滴多的时候,你就会很头疼了. 推荐一款工具DBExportDoc V1.0 For MySQL( ...

  8. MSSQL 更改表结构

    更改表结构: alter TABLE 表1 ALTER COLUMN 列名1 NCHAR(40)

  9. mysql导出word的表结构操作

    mysql导出word的表结构操作 1.首先准备好mysql的相关插件mysql-connector-odbc和DBExportDoc 百度网盘地址: 链接:https://pan.baidu.com ...

随机推荐

  1. UI-了解ISO

    1. iOS学习路线: C语言:数据类型.流程控制.函数.指针.字符串.结构体.枚举.预处理: OC:面向对象.内存管理.分类.协议.Block.KVC/KVO.Foundation框架: iOS基础 ...

  2. Http权威指南(概述篇总结)

    之前的<锋利的jQuery>后面陆续翻完了,实在觉得没什么值得记录的,也就没继续写了,然后看见书架上有 本去年买的<Http权威指南>,其实做web编程的,对于Http协议还是 ...

  3. HTTP返回结果状态码小结

    HTTP 状态码负责表示客户端 HTTP 请求的返回结果.标记服务器端的处理是否正常.通知出现的错误等工作. 一.状态码的类别 状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果.借助状态 ...

  4. 剑指Offer(第二版)面试案例:树中两个节点的最低公共祖先节点

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/74612786冷血之心的博客) 剑指Offer(第二版)面试案例:树 ...

  5. Android 之Navicat for SQLite 数据库介绍

     Navicat for SQLite 是一套专为SQLite 设计的强大数据库管理及开发工具 Navicat for SQLite 是一套专为SQLite 设计的强大数据库管理及开发工具.它可以 ...

  6. 使用redis计数来控制单位时间内对某接口的访问量,防止刷验证码接口之类的

    使用自定义注解的方式,在需要被限制访问频率的方法上加注解即可控制. 看实现方式,基于springboot,aop,redis. 新建Springboot工程,引入redis,aop. 创建注解 pac ...

  7. hashlib摘要算法模块,logging日志,configparser配置文件模块

    一.hashlib模块(摘要算法模块) 1.算法介绍 Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等. 什么是摘要算法呢? 摘要算法又称哈希算法.散列算法.它通过一个函数,把 ...

  8. (一)canvas简介

    <canvas>元素主要用来图形的绘制,通过脚本来完成(通常时js来实现): 可以利用其实现图表,游戏等项目的开发. getContext 获取画布的摸板是2d还是3d strokeRec ...

  9. Apache的Mod_rewrite学习 (RewriteCond重写规则的条件) 转

    RewriteCondSyntax: RewriteCond TestString CondPattern [flags] RewriteCond指令定义一条规则条件.在一条RewriteRule指令 ...

  10. Python学习-数据运算

    在Python中有丰富的算术运算,这使得Python在科学计算领域有着很高的地位,Python可以提供包括四则运算在内的各种算术运算. a = 10 b = 20 print(a-b) #-10 pr ...