5.0和更早版本的MySQL中,在一个已经有很多数据的表上添加或者删除一个索引将非常耗时。CREATE INDEX和DROP INDEX通过创建一个新的空的带有要创建索引的表,然后拷贝存在的行到新表中,同时更新索引,当此时key没有排序时插入条目极慢。在所有的行都被拷贝完成以后,旧表被删除,新表被改名。
从5.1开始,MySQL允许一个存储引擎在不拷贝表数据的情况下创建或者删除一个索引。MySQL 5.1中内建的InnoDB,并没有利用这个特点,新发布的插件带有这个功能。
在InnoDB中,表的行以聚簇索引方式存储,在某些数据库上被称为是索引组织表。改变聚簇索引需要拷贝数据,即使对InnoDB而言也是这样,但是,在InnoDB插件中添加或者删除一个其它类型的索引将会很快,因为并不包含拷贝数据。
这个特性使得你能在刚开始时只创建聚簇索引以加快数据加载,稍后再添加其它的索引。
添加和删除索引并不要求使用新的磁盘文件格式,因此你可以使用InnoDB插件来创建或者删除索引,然后使用标准的内置InnoDB来进行普通的操作。
2.2 例子
一条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 并发的考虑
当一个二类索引被创建或者被删除时,表以共享模式被锁定,任何写将被锁住,但是表仍然可以读。当你修改表的聚簇索引时,表必须排他性锁住,数据必须被拷贝,在新的聚簇索引创建过程中,表上所有操作都被锁住。
在开始执行一个CREATE INDEX或者ALTER TABLE命令之前,必须等到访问表的事务提交或者回滚。除此以外,ALTER TABLE命令如果要创建一个新的聚簇索引,必须等到表上所有的SELECT语句完成。即使原先索引在新的聚簇索引创建之后仍然存在,没有任何跨越了索引创建过程的事务能访问表,因为原先的表必须被删除之后重建。
一个新创建的二类索引将只含有在CREATE TAB或者ALTER TABLE开始执行时表中所存在的数据。一个新创建的索引也只含有在索引创建之前的最近的那个时刻的数据的版本。索引也不含有在CREATE TABLE或者ALTER TABLE之前由事务删除的行。索引也将只含有行的当前版本,在索引创建之前运行的事务不可能创建行的旧版本的更新。
因为一个新创建的索引值包含在索引创建时刻数据的版本,一个查询如果需要看到在索引改变之前的数据,则将不能使用索引。这个限制唯一影响的查询是那些在索引创建开始之前已经开始的事务中的执行语句。此类查询可能会有不可估计的结果。
2.5 崩溃恢复
在执行ALTER TABLE时如果发生崩溃将没有数据丢失,但是对聚簇索引和非聚簇索引恢复是不同的。
对非聚簇索引而言只需要删除部分创建的这些索引,然后重新建立。
对于聚簇索引而言需要将现有数据拷贝到具有期望索引结构的临时表中,在完成后原先表被改名,临时表更名为正式表,然后原先表被删除。
原文地址:http://www.cnblogs.com/jackhub/p/3859930.html