mysql存储——索引

115 阅读3分钟

没有索引的查询

在没有索引的情况下,于我们并不能快速的定位到记录所在的页,所以只能从第一个页沿着双向链表一直往下找,在每一个页的页目录中以此遍历所有的数据,然后对比每条记录是不是符合搜索条件,这就是全局扫描

索引的存储结构

主键索引

在INNODB的数据页中,Compact行格式来实际存储记录的 记录头信息 中有这样一个字段

record_type

  • 0表示普通记录
  • 1表示目录数据结构(索引)
  • 2表示最小记录
  • 3表示最大记录
  • 页内的记录是按照主键的大小顺序排成一个单向链表。
  • 各个存放用户记录的页也是根据页中用户记录的主键大小顺序排成一个双向链表。
  • 存放目录项记录的页分为不同的层次,在同一层次中的页也是根据页中目录项记录的主键大小顺序排成一个双向链表。

image_1caahuomf15m11e5k19v1bf21inq9.png-145.9kB

主键索引示例图:叶子节点中存储的是这一行数据真实的物理地址

普通索引

  • 页内的记录是按照普通列的大小顺序排成一个单向链表。
  • 各个存放用户记录的页也是根据页中记录的普通列大小顺序排成一个双向链表。
  • 存放目录项记录的页分为不同的层次,在同一层次中的页也是根据页中目录项记录的普通列大小顺序排成一个双向链表。

image_1cactc8jg14j91likvmd1h8cn3o4h.png-161.6kB

普通索引示意图:叶子节点中存储的 主键id

联合索引

  • 先把各个记录和页按照c2列进行排序。
  • 在记录的c2列相同的情况下,采用c3列进行排序

image_1d80rmun21al711ok1tvo1i161rnpp.png-172.2kB

思考:如何确定根节点的位置呢?

思考:为什么主键索引存储的是记录真实的物理地址,而普通索引却是主键ID?

  • INNODB数据页本来就设计了页目录这个概念(根据主键id的大小顺寻维护了很多slot,而这些slot可以直接访问到行记录信息),所以主键索引就可以复用这个设计。
  • 如果普通索引页指向真实物理地址的话,如果这行记录的位置发生改变,那么就需要去更新所有的普通索引信息,维护成本很大。

普通索引的创建过程

  • 每当为某个表创建一个B+树索引(聚簇索引不是人为创建的,默认就有)的时候,都会为这个索引创建一个根节点页面。最开始表中没有数据的时候,每个B+树索引对应的根节点中既没有用户记录,也没有目录项记录。
  • 随后向表中插入用户记录时,先把用户记录存储到这个根节点中。
  • 根节点中的可用空间用完时继续插入记录,此时会将根节点中的所有记录复制到一个新分配的页,比如页a中,然后对这个新页进行页分裂的操作,得到另一个新页,比如页b。这时新插入的记录根据键值(也就是聚簇索引中的主键值,二级索引中对应的索引列的值)的大小就会被分配到页a或者页b中,而根节点便升级为存储目录项记录的页。