主要体现在维护代价、空间代价和回表代价。
创建N个二级索引,就需要创建N个B+树,新增数据时不仅需要修改聚簇索引,还需要修改这N个二级索引。在Innodb中,页中的记录都是按索引值从小到大的顺序存放的,新增记录就需要往页中插入数据,现有的页满了就需要新创建一个页,把现有页的部分数据移过去,这就是页分裂
当索引删除或者页分裂会导致数据页有空洞,而重建索引可以重新插入数据,节省空间,使索引更紧凑
重建一个普通索引比如k的语句
alter table T drop index k;
alter table T add index(k);
重建主键索引
alter table T drop primary key;
alter table T add primary key(id);
重建索引k是没有问题的,可以节省空间。但是重建主键索引有问题,无论是删除主键还是创建主键,都会将整个表重建,所以如果上面的语句连着执行的话那么相当于第一个语句白做了。这两个语句,可以用下面这个语句代替
alter table Tengine=InnoDB
需要注意的是,MySQL Server层找引擎拿到的记录数(也就是扫描行数)不一定和引擎内部使用覆盖索引在非主键索引上读取的记录数相等。
可以是联合索引的最左N个字段,也可以是字符串索引的最左M个字符。
建立联合索引的时候,如何安排索引内的字段顺序?
1、对于一个联合索引(a,b),因为支持最左前缀,即不论是精确查找a字段还是模糊查找a都可以走索引,所以一般就不需要再单独创建索引a了。因此,第一个原则就是,如果通过调整顺序,可以少维护一个索引,那个这个顺序往往就是需要优先考虑使用的
2、如果既有联合索引(a,b),又有a,b各自查询,如果查询条件中只有b的语句,那么是不会走联合索引的(因为不满足最左前缀原则),这个时候就不得不再维护一个索引b,这个时候,需要考虑的原则就是空间了
选错索引有很多因素,比如扫描行数,使用临时表,排序等。当出现这种情况后,一种解决的办法是使用force index
强行选择指定的索引,比如下面这个例子
使用索引a只需扫描1000行,而使用索引b需要扫描5000行(采样估计,所以实际扫描的行数不一定相等),所以可以通过强制使用索引a来减少扫描行数
如果把一个InnoDB表的主键删掉,是不是就没有主键,就没办法回表了?并不是,如果创建的表没有主键,或者把一个表的主键删掉了,那么InnoDB会自己生成一个长度为6字节的rowid来作为主键。