1引言
大家好,今天与大家一起分享一下mysqlDDL执行方式。一般来说MySQL分为DDL(定义)和DML(操作)。
DDL:DataDefinitionLanguage,即数据定义语言,那相关的定义操作就是DDL,包括:新建、修改、删除等;相关的命令有:CREATE,ALTER,DROP,TRUNCATE截断表内容(开发期,还是挺常用的),COMMENT为数据字典添加备注。
DML:DataManipulationLanguage,即数据操作语言,即处理数据库中数据的操作就是DML,包括:选取,插入,更新,删除等;相关的命令有:SELECT,INSERT,UPDATE,DELETE,还有LOCKTABLE,以及不常用的CALL–调用一个PL/SQL或Java子程序,EXPLAINPLAN–解析分析数据访问路径。
我们可以认为:
CREATE,ALTER,DROP,TRUNCATE,定义相关的命令就是DDL;
SELECT,INSERT,UPDATE,DELETE,操作处理数据的命令就是DML;
DDL、DML区别:
DML操作是可以手动控制事务的开启、提交和回滚的。
DDL操作是隐性提交的,不能rollback,一定要谨慎哦!
日常开发我们对一条DML语句较为熟悉,很多开发人员都了解sql的执行过程,比较熟悉,但是DDL是如何执行的呢,大部分开发人员可能不太关心,也认为没必要了解,都交给DBA吧。其实不然,了解一些能尽量避开一些ddl的坑,那么下面带大家一起了解一下DDL执行的方式,也算抛砖引玉吧。如有错误,还请各位大佬们指正。
2概述
在MySQL使用过程中,根据业务的需求对表结构进行变更是个普遍的运维操作,这些称为DDL操作。常见的DDL操作有在表上增加新列或给某个列添加索引。
我们常用的易维平台提供了两种方式可执行DDL,包括MySQL原生在线DDL(onlineDDL)以及一种第三方工具pt-osc。
下图是执行方式的性能对比及说明:
本文将对DDL的执行工具之OnlineDDL进行简要介绍及分析,pt-osc会专门再进行介绍。
3介绍
MySQLOnlineDDL功能从5.6版本开始正式引入,发展到现在的8.0版本,经历了多次的调整和完善。其实早在MySQL5.5版本中就加入了INPLACEDDL方式,但是因为实现的问题,依然会阻塞INSERT、UPDATE、DELETE操作,这也是MySQL早期版本长期被吐槽的原因之一。
在MySQL5.6版本以前,最昂贵的数据库操作之一就是执行DDL语句,特别是ALTER语句,因为在修改表时,MySQL会阻塞整个表的读写操作。例如,对表A进行DDL的具体过程如下:
按照表A的定义新建一个表B
对表A加写锁
在表B上执行DDL指定的操作
将A中的数据拷贝到B
释放A的写锁
删除表A
将表B重命名为A
在以上2-4的过程中,如果表A数据量比较大,拷贝到表B的过程会消耗大量时间,并占用额外的存储空间。此外,由于DDL操作占用了表A的写锁,所以表A上的DDL和DML都将阻塞无法提供服务。
如果遇到巨大的表,可能需要几个小时才能执行完成,势必会影响应用程序,因此需要对这些操作进行良好的规划,以避免在高峰时段执行这些更改。对于那些要提供全天候服务(24*7)或维护时间有限的人来说,在大表上执行DDL无疑是一场真正的噩梦。
因此,MySQL官方不断对DDL语句进行增强,自MySQL5.6起,开始支持更多的ALTERTABLE类型操作来避免数据拷贝,同时支持了在线上DDL的过程中不阻塞DML操作,真正意义上的实现了OnlineDDL,即在执行DDL期间允许在不中断数据库服务的情况下执行DML(insert、update、delete)。然而并不是所有的DDL操作都支持在线操作。到了MySQL5.7,在5.6的基础上又增加了一些新的特性,比如:增加了重命名索引支持,支持了数值类型长度的增大和减小,支持了VARCHAR类型的在线增大等。但是基本的实现逻辑和限制条件相比5.6并没有大的变化。
4用法
ALTERTABLEtbl_nameADDPRIMARYKEY(column),ALGORITHM=INPLACE,LOCK=NONE;
ALTER语句中可以指定参数ALGORITHM和LOCK分别指定DDL执行的算法模式和DDL期间DML的锁控制模式。
ALGORITHM=INPLACE表示执行DDL的过程中不发生表拷贝,过程中允许并发执行DML(INPLACE不需要像COPY一样占用大量的磁盘I/O和CPU,减少了数据库负载。同时减少了bufferpool的使用,避免bufferpool中原有的查询缓存被大量删除而导致的性能问题)。
如果设置ALGORITHM=COPY,DDL就会按MySQL5.6之前的方式,采用表拷贝的方式进行,过程中会阻塞所有的DML。另外也可以设置ALGORITHEM=DAFAULT,让MySQL以尽量保证DML并发操作的原则选择执行方式。
LOCK=NONE表示对DML操作不加锁,DDL过程中允许所有的DML操作。此外还有EXCLUSIVE(持有排它锁,阻塞所有的请求,适用于需要尽快完成DDL或者服务库空闲的场景)、SHARED(允许SELECT,但是阻塞INSERTUPDATEDELETE,适用于数据仓库等可以允许数据写入延迟的场景)和DEFAULT(根据DDL的类型,在保证最大并发的原则下来选择LOCK的取值)。
5两种算法
第一种Copy:
按照原表定义创建一个新的临时表;
对原表加写锁(禁止DML,允许select);
在步骤1建立的临时表执行DDL;
将原表中的数据copy到临时表;
释放原表的写锁;
将原表删除,并将临时表重命名为原表。
从上可见,采用copy方式期间需要锁表,禁止DML,因此是非Online的。比如:删除主键、修改列类型、修改字符集,这些操作会导致行记录格式发生变化(无法通过全量+增量实现Online)。
第二种Inplace:
在原表上进行更改,不需要生成临时表,不需要进行数据copy的过程。根据是否行记录格式,又可分为两类:
rebuild:需要重建表(重新组织聚簇索引)。比如optimizetable、添加索引、添加/删除列、修改列NULL/NOTNULL属性等;
no-rebuild:不需要重建表,只需要修改表的元数据,比如删除索引、修改列名、修改列默认值、修改列自增值等。
对于rebuild方式实现Online是通过缓存DDL期间的DML,待DDL完成之后,将DML应用到表上来实现的。例如,执行一个altertableAengine=InnoDB;重建表的DDL其大致流程如下:
建立一个临时文件,扫描表A主键的所有数据页;
用数据页中表A的记录生成B+树,存储到临时文件中;
生成临时文件的过程中,将所有对A的操作记录在一个日志文件(rowlog)中;
临时文件生成后,将日志文件中的操作应用到临时文件,得到一个逻辑数据上与表A相同的数据文件;
用临时文件替换表A的数据文件。
说明:
在copy数据到新表期间,在原表上是加的MDL读锁(允许DML,禁止DDL);
在应用增量期间对原表加MDL写锁(禁止DML和DDL);
根据表A重建出来的数据是放在tmp_file里的,这个临时文件是InnoDB在内部创建出来的,整个DDL过程都在InnoDB内部完成。对于server层来说,没有把数据挪动到临时表,是一个原地操作,这就是”inplace”名称的来源。
使用Inplace方式执行的DDL,发生错误或被kill时,需要一定时间的回滚期,执行时间越长,回滚时间越长。使用Copy方式执行的DDL,需要记录过程中的undo和redo日志,同时会消耗bufferpool的资源,效率较低,优点是可以快速停止。不过并不是所有的DDL操作都能用INPLACE的方式执行,具体的支持情况可以在(在线DDL操作)中查看。
以下是常见DDL操作: