InnoDB的索引模型


在InnoDB中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。

  • InnoDB使用了B+树索引模型,所以数据都是存储在B+树中的。
  • 每一个索引在InnoDB里面对应一棵 B+ 树。

InnoDB中表索引示例:

创建一个表,其主键为ID,表中有字段k、name,并且在k上有索引,以下是

create table T(
    id int primary key, 
    k int not null, 
    name varchar(16),
    index (k)
)engine=InnoDB;

表中行R1到行R5的(ID,k)值分别为(100,1)、(200,2)、(300,3)、(500,5)和(600,6),两棵树的示例示意图如下:

根据叶子节点的内容,索引类型分为主键索引和非主键索引;主键索引的叶子节点存的是整行数据。

  • 在InnoDB里,主键索引也被称为聚簇索引(clustered index)。
  • 在InnoDB里,非主键索引也被称为二级索引(secondary index);非主键索引的叶子节点内容是主键的值。

基于主键索引和普通索引的查询有什么区别?

如果语句是select * from T where ID = 500,即主键查询方式,则只需要搜索ID这棵B+树。
如果语句是select * from T where k = 5,即普通索引查询方式,则需要先搜索k索引树,得到ID的值为500,再到ID 索引树搜索一次;这个过程称为回,即基于非主键索引的查询需要多扫描一棵索引树。

因此,我们在应用中应该尽量使用主键查询。


索引维护

B+树为了维护索引有序性,在插入新值的时候需要做必要的维护。

以上图为例,如果插入新的行ID值为700,则只需要在R5的记录后面插入一个新记录;如果新插入的ID值为400,则需要逻辑上挪动后面的数据,空出位置。
而更糟的情况是,如果R5所在的数据页已经满了,根据B+树的算法,这时候需要申请一个新的数据页,然后挪动部分数据过去;这个过程称为页分裂。

页分裂的过程会影响性能,除了性能外,页分裂操作还影响数据页的利用率;原本放在一个页的数据,现在分到两个页中,整体空间利用率降低大约50%。
当相邻两个页由于删除了数据,利用率很低之后,会将数据页做合并;该过程称为合并,可以认为是分裂过程的逆过程。


自增主键

自增主键是指自增列上定义的主键,在建表语句中一般是这么定义的: NOT NULL PRIMARY KEY AUTO_INCREMENT。

插入新记录的时候可以不指定ID的值,系统会获取当前ID最大值,加1作为下一条记录的ID值。

  • 自增主键的插入数据模式,符合递增插入的场景;每次插入一条新记录,都是追加操作,不涉及到挪动其他记录,也不会触发叶子节点的分裂。
  • 业务逻辑的字段做主键,则往往不容易保证有序插入,这样写数据成本相对较高;除了考虑性能外,我们还可以从存储空间的角度来看。

从性能和存储空间方面考量,自增主键往往是更合理的选择。
有些业务的场景需求是这样的:只有一个索引;该索引必须是唯一索引,这时候我们就要优先考虑“尽量使用主键查询”原则,直接将这个索引设置为主键,可以避免每次查询需要搜索两棵树。

文档更新时间: 2019-12-10 20:17   作者:闻骏