MySQL各版本,对于add Index的处理方式是不同的,主要有三种:
(1)Copy Table方式
这是InnoDB最早支持的创建索引的方式。顾名思义,创建索引是通过临时表拷贝的方式实现的。
新建一个带有新索引的临时表,将原表数据全部拷贝到临时表,然后Rename,完成创建索引的操作。
这个方式创建索引,创建过程中,原表是可读的。但是会消耗一倍的存储空间。
(2)Inplace方式
这是原生MySQL 5.5,以及innodb_plugin中提供的创建索引的方式。所谓Inplace,也就是索引创建在原表上直接进行,不会拷贝临时表。相对于Copy Table方式,这是一个进步。
Inplace方式创建索引,创建过程中,原表同样可读的,但是不可写。
(3)Online方式
这是MySQL 5.6.7中提供的创建索引的方式。无论是Copy Table方式,还是Inplace方式,创建索引的过程中,原表只能允许读取,不可写。对应用有较大的限制,因此MySQL最新版本中,InnoDB支持了所谓的Online方式创建索引。
InnoDB的Online Add Index,首先是Inplace方式创建索引,无需使用临时表。在遍历聚簇索引,收集记录并插入到新索引的过程中,原表记录可修改。而修改的记录保存在Row Log中。当聚簇索引遍历完毕,并全部插入到新索引之后,重放Row Log中的记录修改,使得新索引与聚簇索引记录达到一致状态。
与Copy Table方式相比,Online Add Index采用的是Inplace方式,无需Copy Table,减少了空间开销;与此同时,Online Add Index只有在重放Row Log最后一个Block时锁表,减少了锁表的时间。
与Inplace方式相比,Online Add Index吸收了Inplace方式的优势,却减少了锁表的时间。
1.Inplace add Index
测试表
?
123 | create table t1 (a int primary key , b int )engine=innodb; insert into t1 values (1,1),(2,2),(3,3),(4,4); |
Inplace Add Index处理流程
SQL
?
1 | alter table t1 add index idx_t1_b(b); |
处理流程
?
sql_table.cc::mysql_alter_table(); // 判断当前操作是否可以进行Inplace实现,不可进行Inplace Alter 的包括: // 1. Auto Increment字段修改; // 2. 列重命名; // 3. 行存储格式修改;等 mysql_compare_tables() -> ha_innobase::check_if_incompatible_data(); // Inplace创建索引第一阶段(主要阶段) handler0alter.cc::add_index(); … // 创建索引数据字典 row0merge.c::row_merge_create_index(); index = dict_mem_index_create(); // 每个索引数据字典上,有一个trx_id,记录创建此索引的事务 // 此trx_id有何功能,接着往下看 index ->trx_id = trx_id; // 读取聚簇索引,构造新索引的项,排序并插入新索引 row0merge.c::row_merge_build_indexes(); // 读取聚簇索引,注意:只读取其中的非删除项 // 跳过所有删除项,为什么可以这么做?往下看 row_merge_read_clustered_index(); // 文件排序 row_merge_sort(); // 顺序读取排序文件中的索引项,逐个插入新建索引中 row_merge_insert_index_tuples(); // 等待打开当前表的所有只读事务提交 sql_base.cc::wait_while_table_is_used(); // 创建索引结束,做最后的清理工作 handler0alter.cc::final_add_index(); // Inplace add Index 完毕 |
Inplace Add Index实现分析
在索引创建完成之后ÿ