缺点有:
插入性能依赖于插入顺序,如果我们按照主键进行升序插入,那么插入数据的效率肯定是最高的,否则可能会出现页分裂,严重影响性能。因此,对于InnoDB引擎,我们一般会定义一个自增的列为主键。
更新主键的代价很高。更新主键将导致被更新的行移动,我们一般定义,在InnoDB引擎中,主键不可更新。
二级索引(后面介绍)要经过两次索引查找,一次找到主键值,第二次根据主键值找到行数据。
聚簇索引有以下几点需要注意:
对于Mysql数据库,MyISAM搜索引擎一般没有聚簇索引,InnoDB支持聚簇索引。
由于数据的物理存储方式只能有一种,一个表只能有一个聚簇索引,一般就是使用主键;如果没有指定主键,InnoDB会自动选择一个非空唯一索引构建聚簇索引;如果没有合适的字段,InnoDB会隐式的创建主键构建聚簇索引。
3.2 二级索引
二级索引又称为非聚簇索引,辅助索引。一个表中只允许有一个聚簇索引,但是允许有多个二级索引。如果我们需要依赖非主键进行查找,就需要二级索引了。
如下图,二级索引的叶子节点并不会存储完整的数据,只是存储了建立索引的列的值与主键值。
我们如果需要进行如下查找:
select * form index_demo where c2 = 4
需要先在二级索引中查找到对应的数据项,也就是主键为1,4,10的记录,再到聚簇索引中去查找对应主键值的数据,这个过程我们称之为回表。
对于聚簇索引,数据的查询效率更高(不用回表)。但是对于非聚簇索引,更新数据的效率更高,比如我们更新一个记录的c3列的值,对应的聚簇索引的值也需要进行更新,但是c2的二级索引并没有存储c3的数据,因此不用更新。
3.3 联合索引
严格来说,联合索引属于非聚簇索引。设想如下场景。
(1)对于数据基于c2排序
(2)如果c2数据相同则基于c3排序
这种场景就可以建立联合索引。
3.4.InnoDB的B+树注意事项
3.4.1 根页面位置万年不动
前面我们在介绍时,为了方便大家的理解,先把叶子节点构建了出来,然后往上增加层次。实际上,B+树的形成过程是这样的。
当我们创建一个新的索引时(或者主键自动生成新的索引时),初始时将会创建一个节点作为根节点,此时根节点中没有用户记录,也没有数据项记录。
当插入记录时,记录会被插入到根节点。
当根节点的记录满了,会分配一个新的数据页,比如数据页A,将根节点的数据全部拷贝到数据页A中,然后数据页进行页分裂操作得到页B,此时插入数据时再根据键值大小(主键值大小或者索引列值大小)决定插入到数据页B中还是数据页A中。
根节点会晋升为目录页。
根节点万年不动的原则保证InnoDB数据需要使用某个索引时可以在固定位置取出根节点的页号,从而来访问这个索引。
3.4.2 内节点中目录项记录具有唯一性
我们知道B+树的目录页中存储的记录为页号+索引列数据,这样的描述其实并不严谨。
假设index_demo表中的数据如下表。
此时建立的二级索引B+树如下图。
如果我们需要增加一个记录(9,1,‘c’),我们是应该把这个记录添加到页4还是页5呢?
因此我们必须要求内节点(非叶子节点)的记录(除页号)是唯一的。如何能够实现呢?我们可以自然联想到主键是唯一的。因此下图才是我们实际上真正构建的二级索引的B+树。
此时添加记录(9,1,‘c’)就不迷惑了。我们先判断c2一样,再判断主键值,可以确定应该在页5中添加数据。
3.4.3 一个页面最少要存储两条记录
如果一个页面的记录数少于两条,甚至都无法分为二叉树,只是简单的单向连接。
4.MyISam的索引方案
4.1 不同存储引擎索引的区别
B+树适用的存储引擎如下所示。注:MySql官方中写的B-Tree
就是我们所理解的B+树。
InnoDBheMyISAM默认索引都是B-Tree
,不过MyISAM中叶子节点data
域中存放的是数据记录的地址。而Memory
支持的默认索引是Hash
索引。
4.2 MyISam索引的原理
下面我们将介绍MyISam的索引原理。MyISam使用myd文件存储数据,用myi文件存储索引,MyISam的存储原理与InnoDB的聚簇索引的存储原理显然不同(索引即数据,数据即索引)。实际上,MyISam中根本不存在聚集索引的概念,它的索引都相当于二级索引。
其索引存储示例如下。
上图的col1
是主键,一般我们都是按照主键递增来增加数据的 ,但如果我们增加一条主键为3的数据,还需要进行重新排序吗?答案是否,它会被直接添加到表格后,不进行排序。
实际上如果针对col2
建立索引,与基于主键构建索引在结构上并没有什么不同。4.3 MyISam与InnoDB索引方案的对比
MyISam的索引不存储记录的数据值(或主键值),只存储数据地址,一定需要进行回表操作。
InnoDB的数据文件与索引文件是同一个,MyISam的数据文件与索引文件是分离的。
MyISam回表操作十分快速,因为是拿着地址的偏移量直接到文件中取数据。
InnoDB必须要有主键(如果没有会隐式指定),MyISam没有聚簇索引与二级索引的说法,不需要在二级索引中查找到主键值后再去聚簇索引中查询回表,因此并不是必须需要有主键。当然,我们为了查询方便,也会对该存储引擎的表设置索引。
4.4 索引方案与索引优化的关系
了解不同存储引擎的存储方案有利于我们进行索引优化。
例1:
InnoDB搜索引擎的主键值就不宜设置的过长,因为在所有二级索引中都需要对主键值进行存储。
例2:
用非单调(递增、减)字段在InnoDB存储引擎的表中做主键不合适。因为InnoDB的数据文件本身就是一棵B+树,会基于主键建立聚簇索引。导致我们在插入数据时频繁的发生页分裂。