1. InnoDB快速索引创建
InnoDB快速索引创建,即在表中已经存在大量数据的情况下,能够快速创建和删除辅助索引的能力。
1.1 背景
对于老版本的MySQL,在InnoDB表中已经存在数据的情况下,对其添加或删除索引的过程十分缓慢,那时create index和drop index语句的工作方式为:
① 创建一个空的且带有目标索引结构的新表;
② 逐行拷贝数据行到新表,插入新行的同时更新索引;
③ 全部拷贝完后,删除旧表,并将新表重命名为旧表名字;
1.2 版本要求
从MySQL 5.5开始,为InnoDB表创建和删除辅助索引不再需要复制整个表的内容,从而使得操作速度大为提升。
1.3 适用范围
快速索引创建的性能加速适用于辅助索引,不适用于主键索引。InnoDB表中的数据行存储在基于主键组织的聚簇索引中,形成某些数据库系统称为的“索引组织表”。因为表结构与主键紧密相关,因此重定义主键索引总是需要复制表中的数据。
1.3 方法技巧
这种新机制通常也意味着,你可以使用如下方法加速索引表的创建和加载:先创建只有聚簇索引的表,然后加载数据,最后再添加辅助索引
1.4 语法
InnoDB快速索引创建的语法仍旧是create index, drop index, alter table
◇ alter table
你可以在一条alter table语句中为一个表同时创建多个索引,而且由于只需要扫描一次聚簇索引,所以这种做法的效率也更高。例如:
alter table tbl_name add index (B), add unique index (C);
如果在alter table语句之前已经有大量的数据行被插入到表中,那么先插入数据后添加辅助索引将比先添加辅助索引后加载数据要快得多
◇ crate index
你也可以一次创建一个索引,但此时每条create index语句都需要扫描一次聚簇索引,因此效率上不如上面的alter table,例如:
create index B on tbl_name (B);
create unique index C on tbl_name (C);
◇ drop index
删除InnoDB表的辅助索引同样也不需要复制表中的数据,你可以在一条alter table语句中同时删除多个索引,或者使用多个drop index语句。例如:
alter table tbl_name drop index B, drop index C;
或者
drop index B on tbl_name;
drop index C on tbl_name;
1.5 实现细节
☆ InnoDB有两种类型的索引:聚簇索引和辅助索引。因为聚簇索引把数据值存储在B-tree节点里面,所以添加或删除聚簇索引总是会引发数据复制,并创建表的新副本。同时因为每个辅助索引都包含了主键值的副本,所以当你修改主键时,全部辅助索引都需要重新创建;
☆ 删除辅助索引很简单。服务器只需要更新内部的InnoDB系统表和MySQL数据字典表,以反映索引不再存在的事实即可。同时InnoDB会把该索引占用的空间返还给索引所在的表空间,以便新索引或其它表的数据行可以使用;
☆ 添加辅助索引时,InnoDB会对表进行扫描,并使用内存缓冲区和临时文件按辅助索引列的列值对数据行进行排序。然后B-tree就以键值序被创建,这比以随机顺序把行插入索引更有效。由于B树节点被填满后自动分裂,所以以这种方式构建索引会导致索引具有更高的填充因子,从而使后续访问更高效;
1.6 并发问题
☆ 创建辅助索引
① 创建或删除InnoDB辅助索引时,表被锁定在共享模式下。此时,任何写操作都将被阻塞,但读操作不受影响;
② 创建InnoDB辅助索引的create index和alter table语句开始执行后,对该表可以查询,但不能更新;
☆ 修改聚簇索引
① 更改表的聚簇索引时,由于必须复制数据,所以表将以独占模式被锁定。因此,在创建新的聚簇索引期间,表上的所有操作都将被阻塞;
② 修改InnoDB聚簇索引的alter table语句开始执行后,所有的查询也必须等待,直到操作完成;
③ 修改主键的alter table语句开始执行后,任何事务都不可以访问该表,因为在聚簇索引重构期间老表已经被删除;
☆ 语句执行
① 对于InnoDB表,create index和alter table语句总是会等待当前正在访问表的事物提交或回滚;
② 重定义InnoDB主键的alter table操作会等待当前正在访问该表的所有select语句执行完,或是等待其所在的事物提交;
☆ 内容
新创建的辅助索引只包括create index和alter table语句开始执行时表中已提交的数据,而不包括未提交数据、老版本数据(MVCC)和已标记为删除但还未删除的数据
1.7 重建聚簇索引的过程
MySQL创建新的聚簇索引的过程为:创建一个具有目标索引结构的临时表,然后从原表向临时表复制数据。一旦数据复制完成,原表被重命名为一个其它的临时名字,而临时表被赋予原表的名字,最后一步是从数据库删除原表。
重建InnoDB聚簇索引需要将数据拷贝到一个全新的聚簇索引。请注意,所有的InnoDB表都以聚簇索引形式存储。
1.8 崩溃恢复
在alter table语句执行期间,如果服务器崩溃,没有数据会丢失。但是聚簇索引和辅助索引的崩溃恢复过程是不同的:
① 如果在创建InnoDB辅助索引时服务器崩溃,则在恢复时,MySQL将删除任何部分创建的索引。你必须重新运行alter table或create index语句;
② InnoDB聚簇索引的崩溃恢复较为复杂,请联系MySQL支持;
1.9 局限性
① 同时包含了drop index和add index,且两者指定的是同一个索引的alter table语句,使用的是表复制,而不是快速索引创建;
② 临时表的索引创建使用的是表复制,而不是快速索引创建;
③ 为避免InnoDB数据字典和MySQL数据字典之间的一致性问题,当使用alter table ... change语法重命名列时,使用的是表复制而不是快速索引创建;
④ MySQL 5.5不支持高效地创建或删除外键约束。因此,如果使用alter table添加或删除references约束,子表将被复制,而不是使用快速索引创建;
⑤ InnoDB表的optimize table被自动映射为alter table操作,以重建表、更新索引统计信息,并释放聚簇索引中未使用的空间。此操作无法使用快速索引创建。同时,辅助索引也无法被高效地创建,因为辅助索引的键是根据它们在主键中出现的顺序插入的。
1.10 实战
对一个1000W行的表,删除辅助索引耗时52min