0、导读
InnoDB表的索引有哪些特性,以及索引组织结构是怎样的
1、InnoDB聚集索引特点
我们知道,InnoDB引擎的聚集索引组织表,必然会有一个聚集索引。
行数据(row data)存储在聚集索引的叶子节点(除了发生overflow的列,参见 ,后面简称 “前置文”),并且其存储的相对顺序取决于聚集索引的顺序。这里说相对顺序而不是物理顺序,是因为叶子节点数据页中,行数据的物理顺序和相对顺序可能并不是一致的,放在后面会讲。
InnoDB聚集索引的选择先后顺序是这样的:
-
如果有显式定义的主键(PRIMARY KEY),则会选择该主键作为聚集索引
-
否则,选择第一个所有列都不允许为NULL的唯一索引
-
若前两者都没有,则InnoDB会选择内置的DB_ROW_ID作为聚集索引,命名为GEN_CLUST_INDEX
特别提醒: DB_ROW_ID占用6个字节,每次自增,且是整个实例内全局分配。也就是说,当前实例如果有多个表都采用了内置的DB_ROW_ID作为聚集索引,则在这些表插入新数据时,他们的内置DB_ROW_ID值并不是连续的,而是跳跃的。像下面这样:
t1表的ROW_ID:1、3、7、10
t2表的ROW_ID:2、4、5、6、8、9
2、InnoDB索引结构
InnoDB默认的索引数据结构采用B+树(空间索引采用R树),索引数据存储在叶子节点。
InnoDB的基本I/O存储单位是数据页(page),一个page默认是16KB。我们在 前置文 说过,每个page默认会预留1/16空闲空间用于后续数据“变长”更新所需,因此在最理想的顺序插入状态下,其产生的碎片也最少,这时候差不多能填满15/16的page空间。如果是随机写入的话,则page空间利用率大概是1/2 ~ 15/16。
当 row_format = DYNAMIC|COMPRESSED 时,索引最多长度为 3072字节,当 row_format = REDUNDANT|COMPACT 时,索引最大长度为 767字节。当page size不是默认的16KB时,最大索引长度限制也会跟着发生变化。
我们接下来分别验证关于InnoDB索引的基本结构特点。
首先创建如下测试表:
[root@yejr.me] [innodb]> CREATE TABLE `t1` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`c1` int(10) unsigned NOT NULL DEFAULT '0',
`c2` varchar(100) NOT NULL,
`c3` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
KEY `c1` (`c1`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
set @uuid1=uuid(); set @uuid2=uuid();
insert into t1 select 0, round(rand()*1024),
@uuid1, concat(@uuid1, @uuid2);
# 用innodb_ruby工具查看
[root@yejr.me]# innodb_space -s ibdata1 -T innodb/t1 space-indexes
id name root fseg fseg_id used allocated fill_factor
238 PRIMARY 3 internal 1 1 1 100.00%
238 PRIMARY 3 leaf 2 0 0 0.00%
239 c1 4 internal 3 1 1 100.00%
239 c1 4 leaf 4 0 0 0.0
# 用innblock工具查看
[root@yejr.me]# innblock innodb/t1.ibd scan 16
...
===INDEX_ID:238
level0 total block is (1)
block_no: 3,level: 0|*|
===INDEX_ID:239
level0 total block is (1)
block_no: 4,level: 0|*|
索引ID | 索引类型 | 根节点page no | 索引层高 |
---|---|---|---|
238 | 主键索引(聚集索引) | 3 | 1 |
239 | 辅助索引 | 4 | 1 |