导读:在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. iOS中UIWebView执行JS代码(UIWebView)

    iOS中UIWebView执行JS代码(UIWebView) 有时候iOS开发过程中使用 UIWebView 经常需要加载网页,但是网页中有很多明显的标记让人一眼就能看出来是加载的网页,而我们又不想被 ...

  2. CentOS上安装Hadoop2.7,添加数据节点,运行wordcount

    安装hadoop的步骤比较繁琐,但是并不难. 在CentOS上安装Hadoop2.7 1. 安装 CentOS,注:图形界面并无必要 2. 在CentOS里设置静态IP,手工编辑如下4个文件 /etc ...

  3. ReOut

    package JBJADV003;import java.io.*;public class ReOut { /** * @param args */ public static void main ...

  4. Pandas数据处理实战:福布斯全球上市企业排行榜数据整理

    手头现在有一份福布斯2016年全球上市企业2000强排行榜的数据,但原始数据并不规范,需要处理后才能进一步使用. 本文通过实例操作来介绍用pandas进行数据整理. 照例先说下我的运行环境,如下: w ...

  5. JavaWeb 后端 <七> 之 mvc3层架构

  6. lvs讲解

    作者写的就是好呀,简单明了,安逸的我也不知道早点看看,非得等到找工作了,在这里临时抱佛脚,以后再过来添加我自己的总结 http://www.linuxvirtualserver.org/zh/

  7. spring 框架的xml文件如何读取properties文件数据

    spring 框架的xml文件如何读取properties文件数据 第一步:在spring配置文件中 注意:value可以多配置几个properties文件 <bean id="pro ...

  8. mongoDB创建数据库用户

    运行mongo.exe >use demo //切换到要创建用户的数据库 >db.createUser({user: "admin",pwd: "admin& ...

  9. Java - 初始化

    用构造器保证初始化 构造器名称必须与类名完全相同,所以“每个方法首字母必须小写”的风格不适合构造器. 不接受任何参数的构造器叫做默认构造器.Java文档中通常叫做无参构造器. 构造器没有返回值,但与返 ...

  10. HashMap TreeMap ConcurrentHashMap 源码

    1 HashMap java se 1.6 1.1 父类 java.lang.Object 继承者 java.util.AbstractMap<K,V> 继承者 java.util.Has ...