什么是OnlineDDL?在了解OnlineDDL之前,我们先来了解一下什么是DDL。说DDL,就不得不提一下它的另外两个:DML和DCL。

他们三者的区别如下:

  DDL:data definition language,数据定义语言,用来定义数据的语句。例如我们平时的create table,create index,create function等。

  DML:data manipulation language,数据修改语言,用来操作数据的语句。例如我们平时的select,insert,update,delete语句。

  DCL:data control language,数据控制语言,用来定义数据访问控制的语句。例如我们平时的grant,revoke等。而OnlineDDL是指在线的数据定义语言,所谓的在线是指:在数据表在不停止服务的情况下来应用我们的DDL语句,即表在应用DDL语句的时候,仍然可以提供读写的服务。

注意:在执行OnlineDDL之前,要在非业务高峰期去执行,并要确认待执行的表上面没有未提交的事务、锁等信息。可以通过如下的SQL语句查看是否有事务和锁等信息。

  SELECT * FROM information_schema.innodb_locks;

  SELECT * FROM information_schema.innodb_trx;

  SELECT * FROM information_schema.innodb_lock_waits;

  SELECT * FROM information_schema.PROCESSLIST;

小表我们可以直接处理,千万及亿级数量,我们之所以不敢直接干的原因,大概是担心以下问题的发生,这也是我们经常锁的MySQL的online DDL要格外注意的原因。

  1.表被锁上,不能进行正常的读写或者写。

  2.不能写还好一下,最怕是连读都不能读。

  3.如果有主从复制架构,担心主从同步出现大幅度的延迟。

解决方法:

  一.在MySQL5.6和5.7版本中,默认情况下,MySQL就是支持online的DDL操作的,在online的DDL语句执行的过程中,MySQL会尽量少使用锁的限制,我们不需要特殊的操作来启用它。MySQL在选择的时候,尽量少使用锁,但是不排除它会选择使用锁。而如果我担心它选择了锁而导致我们的表不能读也不能写,显然这不是我们想要的结果,我们希望:如果选择了锁就不要执行,直接退出执行;如果没有选择锁就执行。想要达到我们希望的这个效果,该怎么做呢?

可以在执行我们的online DDL语句的时候,使用ALGORITHM和LOCK关键字,这两个关键字在我们的DDL语句的最后面,用逗号隔开即可。示例如下:

  ALTER TABLE tbl_name ADD COLUMN col_name col_type, ALGORITHM=INPLACE, LOCK=NONE;

其中的ALGORITHM有如下选项

  INPLACE:替换:直接在原表上面执行DDL的操作。

  COPY:复制:使用一种临时表的方式,克隆出一个临时表,在临时表上执行DDL,然后再把数据导入到临时表中,在重命名等。这期间需要多出一倍的磁盘空间来支撑这样的 操作。执行期间,表不允许DML的操作。

  DEFAULT:默认方式,有MySQL自己选择,优先使用INPLACE的方式。

其中的LOCK有如下选项

  SHARE:共享锁,执行DDL的表可以读,但是不可以写。

  NONE:没有任何限制,执行DDL的表可读可写。EXCLUSIVE:排它锁,执行DDL的表不可以读,也不可以写。

  DEFAULT:默认值,也就是在DDL语句中不指定LOCK子句的时候使用的默认值。如果指定LOCK的值为DEFAULT,那就是交给MySQL子句去觉得锁还是不锁表。不建议使用,如果你确定你的DDL语句不会锁表,你可以不指定lock或者指定它的值为default,否则建议指定它的锁类型。执行DDL操作时,ALGORITHM选项可以不指定,这时候MySQL按照INSTANT、INPLACE、COPY的顺序自动选择合适的模式。也可以指定ALGORITHM=DEFAULT,也是同样的效果。如果指定了ALGORITHM选项,但不支持的话,会直接报错。

  二,使用第三方工具pt-online-schema-change(Percona 工具 PT-OSC(Percona Toolkit Online Schema Change))

    下载地址:https://www.percona.com/downloads/percona-toolkit/LATEST/

    https://www.percona.com/doc/percona-toolkit/LATEST/pt-online-schema-change.html或者使用pt-online-schema-change--help的命令查看帮助信息。

    示例:

      1.在某一个表上增加列,多个列逗号隔开即可

        pt-online-schema-change \--user=dev0 \--password="dev" \ D=demo_db,t=list_detail \--alter " add column taste_type_id varchar(100) DEFAULT NULL COMMENT '品味标签id' AFTER standard_code, add column taste_name varchar(100) DEFAULT NULL COMMENT '品味标签名称' AFTER taste_type_id " \--recursion-method=processlist \--check-interval=35s \--max-lag=35s \--charset=utf8 \--print \--execute

      2.在某一个表上增加索引

        pt-online-schema-change \--user=dev1 \--password="deva" \ D=demo_db,t=list_detail \--alter " add index idx_taste_type_id (taste_type_id) " \--recursion-method=processlist \--check-interval=25s \--max-lag=25s \--charset=utf8mb4 \--print \--execute

      3.在就一个表上删除列

        pt-online-schema-change \--user=dev2 \--password="devb" \ D=demo_db,t=list_detail \--alter " drop column taste_type_id " \--recursion-method=processlist \--check-interval=15s \--max-lag=15s \--charset=gbk \--print \--execute

      4.在某一个表上删除索引

        pt-online-schema-change \--user=dev3 \--password="devc" \ D=demo_db,t=list_detail \--alter " drop index idx_taste_type_id " \--recursion-method=processlist \--check-interval=51s \--max-lag=51s \--charset=utf8mb4 \--print \--execute

  三.冗余字段

    设计表的时候,配置冗余字段。冗余字段设计。为的就是以后业务变更或者扩展的时候,需要增加表中的字段。如果有了这个冗余的字段设计,直接表表名称修改一下就可以了。

  四.主从延迟的规避

    禁止记录bin-log,把DDL语句在主从上分别执行。这个动作仅能避免主从延迟的问题,但是不能解决在执行DDL语句的时候,避免锁表现象的发生。所以,还得需要使用ALGORITHM和LOCK关键字来避免DDL语句运行期间,表不能读写的问题。

    示例:

      set sql_log_bin=off;alter table mytab add colmn mycol varchar(32) after id;