InnoDB支持常见的几种索引:B+树索引、哈希索引、全文索引。
B+树索引
B+树
B+树是一种平衡多路查找树,包含根节点、内部节点、叶子节点(或者没有内部节点的情况,根节点即叶子节点)。B+树具有如下的特性:
- 非叶子节点没有value,只包含key,当它有k个子节点时,则包含k-1个key(k>=2),父节点的key都是子节点中的最大key或最小key,父节点的k-1个key划分出k个区间,对应k个子节点
- 叶子节点既包含key,也包含value,value通常是指向数据的指针,因而B+树的数据被叫做卫星数据;
- 所有的叶子节点包含了全部的key;叶子节点都位于同一层级,具有相同的深度
- 叶子节点按照key的大小顺序排列,通过链表连接在一起
B+树索引
InnoDB使用B+树索引有如下优势:
- 由于叶子节点按照大小排列连接成链表,能够更加方便的进行范围查询、排序、分页
- 由于每个节点可以存储多个key,因此树的出度大,高度低,磁盘IO次数少;
- 叶子节点存储数据,结构紧密,适合大数据量的磁盘存储,同时由于磁盘预读,能够充分利用局部性原理,减少磁盘IO(查询记录附近的数据后续更有可能被查询,但磁盘预读已经将其一并预加载进内存了)
- 由于数据都在叶子节点上,且叶子位于同一层级具有相同的深度,因此数据的查询具有稳定性。
主键索引、非主键索引、复合索引、前缀索引
主键
InnoDB的表必须要有主键,建表时可以指定一个或多个唯一且非空的列作为主键。如果建表时未显示指定主键,InnoDB会自动找到第一个唯一且非空的索引作为主键;如果不存在这样的列,InnoDB会自动创建一个6字节的ROW_ID列作为隐式主键,每插入一条数据自动生成ROW_ID。
主键索引(聚簇索引、聚集索引、一级索引,clustered index)
之所以要有主键(主键索引),因为InnoDB的数据行是按照主键的顺序排列,存储在主键索引的叶节点页中。也就是说,InooDB主键索引和数据是存储在一起的,一张表也只能有一个主键索引。
尽量选自增的短小的id作为主键。自增id每次插入是追加操作,不会触发叶子节点页的分裂和数据的移动;非聚集索引会保存主键的值,因此主键较小,非聚集索引也比较小。
非主键索引(非聚簇索引、非聚集索引、辅助索引、二级索引,secondary index)
非主键索引叶子节点中存储主键值,每次查找数据时,根据索引找到叶子节点中的主键值,根据主键值再到聚簇索引中得到完整的一行记录。
由于二级索引保存的是聚簇索引的值而非指针,当表中数据发生移动时,主键值并非发生改变,二级索引不需要进行调整,减少了维护二级索引的开销。
复合索引(多列索引,Composite Index)
复合索引就是建立在多个列上的索引,相对应的建立在单个列上的索引是独立索引。主键索引和二级索引,既可以是复合索引,也可以是独立索引。 复合索引遵循最左前缀原则,数据将首先按照第一列排序,第一列相等再按照第二列排序,...。
前缀索引
有时候需要索引很长的字符(例如BLOB,TEXT,或者很长的VARCHAR),这样会使得索引又大又慢,此时可以考虑选择使用字符串的前几个字符作为索引,也就是前缀索引。 前缀索引扫描完还需要回表再确认一次,MySQL中无法使用前缀索引进行ORDER BY和GROUP BY,也无法用来进行覆盖扫描。
索引失效
- 当where条件中有or的多个列的筛选时,如果其中存在没有建索引的列,则不会走索引;
- 当where条件中的列存在复合索引中,但不是where不包含索引中该列左边的列时,不会走索引;
- 当查询条件是like,且以%开头时,不会走索引;
- 当查询条件的值的类型与数据库中不一致,需要隐式转换时,不会走索引;
- 当where条件中对索引列进行运算时,不会走索引;
- 当where条件中对索引列使用了函数时,不会走索引;
- 如果mysql觉得全表扫描更快时(数据少),不会走索引;
索引覆盖与回表
回表
由于二级索引只包含索引列的值和主键的值,当通过二级索引查询时,还需要返回不在二级索引上的列,则需要在扫描完二级索引后,获取满足条件的主键,并对主键索引再做一次扫描以通过主键获取到数据行,读取需要的列的值。这个过程叫做回表。
索引覆盖
当查询中所有的列都在索引上时,不需要进行回表即可得到需要列的数据,性能很快。 通常通过对查询列建立联合索引来实现索引覆盖。
三星索引
三星索引,顾名思义,是满足了三个星级的索引。那么,这个三个星级是如何给定的呢?
★☆☆
定义:如果与一个查询相关的索引行是相邻的,或者至少相距足够靠近的话,那这个索引就可以标记上一颗星。
收益:它最小化了必须扫描的索引片的宽度。
实现:把 WHERE 后的等值条件列作为索引最开头的列,如此,必须扫描的索引片宽度就会缩至最短。
★★☆
定义:如果索引行的顺序与查询语句的需求一致,则索引可以标记上第二颗星。
收益:它排除了排序操作。
实现:将 ORDER BY 列加入到索引中,保持列的顺序
★★★
定义:如果索引行中包含查询语句中的所有列,那么这个索引就可以标记上第三颗星。
收益:这避免了访问表的操作(避免了回表操作),只访问索引就可以满足了。
实现:将查询语句中剩余的列都加入到索引中。