导读:在MySQL5.6之前版本,Innodb表的许多DDL操作是非常昂贵。许多ALTER TABLE操作的原理是通过创建新的空表,定义被要求的表选项和索引,然后逐行拷贝已存在记录到新表,在插入行时更新索引。在旧表所有行被拷贝完,旧表被删除和那新表被重命名为旧的表名。MySQL5.5,和MySQL5.1 有了InnoDB Plugin,优化了CREATE INDEX和DROP INDEX 避免表的拷贝行为。这个特性被称为Fast index Creation。MySQL 5.6 加强ALTER TABLE操作许多方式来避免拷贝表。另外加强的允许SELECT查询和INSERTUPDATE,和DELETE(DML)语句被处理当该表正被修改时。这些功能的组合现在被称为online DDL

语法解读:online DDL操作允许alter table 语句指定ALGORITHM,LOCK 子句。

ALGORITHM=inplace,表示DDL操作在原表上就地操作,ALGORITHM=copy ,表示采用以前方式(复制表)进行DDL 操作。DDL没有指定ALGORITHM子句,MySQL会自动选择每种DDL所允许的ALGORITHM子句(并不是所有DDL在所有情况下都支持每种ALGORITHM,如果两种都支持,默认ALGORITHM=inplace优先选择,如果指定某种DDL在某种情况下不允许的ALGORITHM,该执行的DDL 以失败告终)。

LOCK={default|none|shared|exclusive|}是显式指定alter table 的锁级别,default 表是使用所有DDL在不同情况下的默认的锁级别(也是DDL在不同情况下支持最低级别的锁)。LOCK=none不加锁,允许DML,查询并发(注意LOCK=none不是真正表示执行DDL操作不进行锁,在DDL执行真正执行时,还是加排他锁)。LOCK=SHARED不允许DML并发,允许查询。LOCK=exclusive 不允许 DML并发和查询。(alter table 没有显式指定锁的级别,默认情况使用该DDL允许的默认的最低级别锁<也就是看情况>,如果显式指定的锁是该DDL不允许的级别,该DDL以失败中止)

online DDL工作机制:通过ALGORITHM实现DDL操作是复制表还是在原表就地操作,让DDL尽量影响那些需要改变的数据,而不要操作那些不需改变的数据如:对一列设置默认值,仅对该表.frm修改而涉及数据文件。通过LOCK 实现DML,查询的并发。不管锁是哪种级别,在DDL语句正在准备时和在DDL提交时都是以独占方式访问表。而LOCK不同的级别控制是否允许在online DDL操作之前已发起的DML和查询但没有提交和回滚的事务并发。

DDL的影响范围:有些DDL操作仅影响逻辑文件(对一列设置默认值,仅对该表.frm修改不是数据文件。),有些DDL操作影响整个数据文件(重建主键,需要对整个数据进行新的聚集组织),有些DDL操作影响部分数据文件(新增二级索引,二级索引只有主键的值,只需对主键的值进行重构)。

online DDL执行时间:从上面的分析,我可以知道online DDL的执行时间的长短取决多个方面:

1:online DDL 操作的影响范围的大小。

2:online DDL 操作对象的数据量的大小。

3:online DDL 操作时,当前是否已存在需长时间执行的事务

4:online DDL 操作选取ALGORITHM(inplace不一定比copy快)和LOCK的方式

以上因素要综合考虑,才能使online DDL 操作更顺利和更高效。

OnLine DDL后innodb的索引

5.0和更早版本的MySQL中,在一个已经有很多数据的表上添加或者删除一个索引将非常耗时。CREATE INDEX和DROP INDEX通过创建一个新的空的带有要创建索引的表,然后拷贝存在的行到新表中,同时更新索引,当此时key没有排序时插入条目极慢。在所有的行都被拷贝完成以后,旧表被删除,新表被改名。

一条ALTER TABLE命令创建多个索引是可能的。这相对有效,因为聚簇索引只需要被扫描一次。比如

CREATE TABLE T1(A INT PRIMARY KEY, B INT, C CHAR(1)) ENGINE=InnoDB;

INSERT INTO T1 VALUES

(1,2,'a'), (2,3,'b'), (3,2,'c'), (4,3,'d'), (5,2,'e');

COMMIT;

ALTER TABLE T1 ADD INDEX (B), ADD UNIQUE INDEX (C);

上面的命令将创建表T1,在列A上创建聚簇的主键索引,插入几行,然后在列B和C上创建2个新的索引。如果在ALTER TABLE命令之前有很多行,这个方法将比预先创建带有全部索引的表然后加载数据有效。

你也可以一次只创建一个索引,但是每次聚簇索引都会针对CREATE INDEX扫描一次。在InnoDB中删除索引并不要求表数据的任何拷贝,因此一次删多条或者一次删一条是等价的。

重建InnoDB中的聚簇索引总是要求拷贝表中的数据。比如,如果你创建一个表时没有主键,InnoDB将为你选择一个,它可能是第一个UNIQUE key或者NOT NULL的列,或者一个系统产生的key。如果你在后来定义了一个PRIMARY KEY,数据将不得不拷贝。

2.3 实现

InnoDB有2种类型的索引:聚簇索引和二类索引,由于聚簇索引包含数据值于Btree节点之中,添加或者删除一个聚簇索引涉及到数据的拷贝,并将创建一个新的表的拷贝。一个二类索引实际上只包含索引的key和主键的值,这种类型的索引可以在不用拷贝聚簇索引中数据的情况下创建或者删除。进一步,因为二类索引包含着主键的值,当你改变主键定义的时候,将重新创建聚簇索引,所有的二级索引也将重新创建。

删除一个二类索引是简单的,只有内部的InnoDB系统表和MySQL的数据字典表需要被更新来反应索引不再存在的事实。InnoDB将返回索引所使用的空间给表空间,因此新索引或者额外表的行可以使用这些空间。

要添加一个二类索引到存在的表中,InnoDB扫描表,使用内存Buffer和临时文件按照被索引的列的顺序对行进行排序。然后Btree就被建立起来了,这比以随机顺序插入行时保证key的值有序要有效。 因为Btree节点在满了以后会分裂,按照此种方式构建的索引有一个较高的填充因子,对随后的访问具有较好的效率。

2.4 并发的考虑

测试表明对于主键的修改操作,仅rename阶段会短暂的排它锁。

mysql> drop index `PRIMARY` on t1;
Query OK, 300028 rows affected (14.76 sec)
Records: 300028 Duplicates: 0 Warnings: 0

mysql> show profile for query 43;
+----------------------+-----------+
| Status | Duration |
+----------------------+-----------+
| starting | 0.000080 |
| checking permissions | 0.000012 |
| init | 0.000004 |
| Opening tables | 0.000230 |
| setup | 0.000036 |
| creating table | 0.049951 |
| After create | 0.000301 |
| System lock | 0.282387 |
| copy to tmp table | 14.089265 |
| rename result table | 0.332012 |
| end | 0.000036 |
| query end | 0.000012 |
| closing tables | 0.000090 |
| freeing items | 0.003100 |
| cleaning up | 0.000061 |
+----------------------+-----------+
15 rows in set, 1 warning (0.00 sec)

mysql> select * from t1 limit 10;
...
mysql> show profile for query 28;
+--------------------------------+----------+
| Status | Duration |
+--------------------------------+----------+
| starting | 0.000081 |
| checking permissions | 0.000013 |
| Opening tables | 0.000022 |
| Waiting for table metadata loc | 0.254933 |
| Opening tables | 0.001558 |
| init | 0.000070 |
| System lock | 0.000026 |
| optimizing | 0.000013 |
| statistics | 0.000040 |
| preparing | 0.000035 |
| executing | 0.000008 |
| Sending data | 0.000173 |
| end | 0.000014 |
| query end | 0.000032 |
| closing tables | 0.000032 |
| freeing items | 0.000384 |
| cleaning up | 0.000036 |
+--------------------------------+----------+
17 rows in set, 1 warning (0.00 sec)

右边session2中前面在drop index之后执行了很多条查询,都没有阻塞,仅在session中的rename阶段短暂阻塞。

由于Online DDL原因,DML操作也与上面类似,不会长阻塞。但是如果例如drop primay key等操作没有使用online ddl特性,依然要copy to tmp table,那么依然会像myisam一样对DML阻塞。

对于myisam表创建index时<copy to tmp table>,select只有rename时段堵塞,DML被全程阻塞。

InnoDB online DDL与快速索引创建的更多相关文章

  1. (转)Mysql技术内幕InnoDB存储引擎-表&索引算法和锁

    表 原文:http://yingminxing.com/mysql%E6%8A%80%E6%9C%AF%E5%86%85%E5%B9%95innodb%E5%AD%98%E5%82%A8%E5%BC% ...

  2. MySQL技术内幕InnoDB存储引擎(表&索引算法和锁)

    表 4.1.innodb存储引擎表类型 innodb表类似oracle的IOT表(索引聚集表-indexorganized table),在innodb表中每张表都会有一个主键,如果在创建表时没有显示 ...

  3. MySQL InnoDB存储引擎体系架构 —— 索引高级

    转载地址:https://mp.weixin.qq.com/s/HNnzAgUtBoDhhJpsA0fjKQ 世界上只两件东西能震撼人们的心灵:一件是我们心中崇高的道德标准:另一件是我们头顶上灿烂的星 ...

  4. mysql 优化实例之索引创建

    mysql 优化实例之索引创建 优化前: pt-query-degist分析结果: # Query 23: 0.00 QPS, 0.00x concurrency, ID 0x78761E301CC7 ...

  5. substr函数索引创建测试

    技术群里小伙伴,沟通说一条经常查询的SQL缓慢,单表SQL一个列作为条件,列是int数值类型,索引类型默认创建. 一.SQL文本substr函数索引创建测试 ,) nm1 ')需求,将上述SQL执行速 ...

  6. Database基础(二):MySQL索引创建与删除、 MySQL存储引擎的配置

    一.MySQL索引创建与删除 目标: 本案例要求熟悉MySQL索引的类型及操作方法,主要练习以下任务: 普通索引.唯一索引.主键索引的创建/删除 自增主键索引的创建/删除 建立员工表yg.工资表gz, ...

  7. mysql索引创建和使用细节

    最近困扰自己很久的膝盖积液手术终于做完,在家养伤,逛技术博客看到easyswoole开发组成员仙士可博客有关mysql索引方面的知识,自己打算重温下. 正常业务起步数据表数据量较少,不用考虑使用索引, ...

  8. 数据页结构 .InnoDb行格式、以及索引底层原理分析

    局部性原理 局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中. 首先要明白局部性原理能解决的是什么问题,也就是主存容量远远比缓存大, CP ...

  9. mysql InnoDB引擎是否支持hash索引

    看一下mysql官方文档:https://dev.mysql.com/doc/refman/5.7/en/create-index.html , 从上面的图中可以得知,mysql 是支持hash索引的 ...

随机推荐

  1. python迭代器生成器(三)

    扩展的列表解析语法 今天接着昨天的继续写. 列表解析可以变得更加复杂---例如,它可以包含嵌套的循环,也可能被编写为一系列的for子句.(这里只是简单介绍一下,以后再说这个语法的问题) 例如:构建一个 ...

  2. 在当前光标处按指定属性显示字符 - BOIS中断

    在当前光标处按指定属性显示字符 - BOIS中断 最简单的调试方式是打印. 编写MBR时,判断MBR是否加载并运行,最直接的方式就是打印一个字符. INT 0x10 功能描述: 在当前光标处按指定属性 ...

  3. tp框架为什么验证码加载不出来?----- ob_clean() 可解决

    在用tp做验证码时,代码逻辑都正确,但就是加载不出图片来,如何解决呢?在创建验证码之前加上 ob_clean(); public function haha(){ ob_clean(); $v = n ...

  4. 跟我一起读postgresql源码(六)——Executor(查询执行模块之——查询执行策略)

    时光荏苒,岁月如梭.楼主已经很久没有更新了.之前说好的一周一更的没有做到.实在是事出有因,没能静下心来好好看代码.当然这不能作为我不更新的理由,时间挤挤还是有的,拖了这么久,该再写点东西了,不然人就怠 ...

  5. Java自学手记——注解

    注意区分注释和注解,注释是给人看的,注解是给程序看的. 注解的作用是代替配置文件,在servlet3.0中,就可以不再使用web.xml文件,而是所有配置都是用注解!比如注解类 @WebServlet ...

  6. C#将datatable的某一列转换成json格式的字符串

    将datatable的某一列转换成json格式的字符串(转换完后自己在字符串前后加{}) /// <summary> ///DataTable装换 Column数据 组合成json 现在的 ...

  7. 大数据平台常见异常-zookeeper

    本文主要阐述大数据平台环境zookeeper常见异常和解决方案 1.Connection reset by peer异常 异常说明 我们现在项目有个任务OneMinuteDataSync是用spark ...

  8. 浅谈身为小白学习Linux系统的四点实用建议

    游戏.办公.安全,可以总结为是方便当代人们在生活中的刚需,我们大都是这些服务的使用者,而把单个功能整合起来那就必须谈到互联网,自然而然通过互联网要将Service发送给Service manageme ...

  9. java 使用spring实现读写分离

    最近上线的项目中数据库数据已经临近饱和,最大的一张表数据已经接近3000W,百万数据的表也有几张,项目要求读数据(select)时间不能超过0.05秒,但实际情况已经不符合要求,explain建立索引 ...

  10. 同一个sql在不同的oracle中执行时间不一样

    最近因为某些原因不得不重新配置服务器的环境,当然就是一些简单的程序运行环境,包括tomcat .oracle和其他的一些.原本觉得还蛮简单的东西,但是当我部署完成后在运行程序的过程中发现了一些隐性因数 ...