mysql之innodb索引结构

前一篇,mysql之innodb存储结构我们了解了mysql的innodb的存储结构。这次我们再来了解innodb的索引结构;

在上一篇中我们说到record_type 有4种属性,其中1表示目录项记录,这次我们重点讲的就是这个。

存储结构

上一篇讲解的时候只是在强调InnoDB的数据页。在页之上有段,段之上有区,之前在讲undo log的时候也强调过这个概念。

借用一张图

表空间(table space)

表空间(Tablespace)是一个逻辑容器,表空间存储的对象是段,在一个表空间中可以有一个或多个段,但是一个段只能属于一个表空间。数据库由一个或多个表空间组成,表空间从管理上可以划分为系统表空间、用户表空间、撤销表空间、临时表空间等。

在 InnoDB 中存在两种表空间的类型:共享表空间和独立表空间。如果是共享表空间就意味着多张表共用一个表空间。如果是独立表空间,就意味着每张表有一个独立的表空间,也就是数据和索引信息都会保存在自己的表空间中。独立的表空间可以在不同的数据库之间进行迁移。可通过命令

mysql > show variables like 'innodb_file_per_table';

查看当前系统启用的表空间类型。目前最新版本已经默认启用独立表空间。

InnoDB把数据保存在表空间内,表空间可以看作是InnoDB存储引擎逻辑结构的最高层。本质上是一个由一个或多个磁盘文件组成的虚拟文件系统。InnoDB用表空间并不只是存储表和索引,还保存了回滚段、双写缓冲区等。

段(segment)

段(Segment)由一个或多个区组成,区在文件系统是一个连续分配的空间(在 InnoDB中是连续的64 个页),不过在段中不要求区与区之间是相邻的。段是数据库中的分配单位,不同类型的数据库对象以不同的段形式存在。当我们创建数据表、索引的时候,就会相应创建对应的段,比如创建一张表时会创建一个表段,创建一个索引时会创建一个索引段。

区(extent)

在InnoDB存储引擎中,一个区会分配64个连续的页。因为 InnoDB 中的页大小默认是 16KB,所以一个区的大小是 64*16KB=1MB。在任何情况下每个区大小都为1MB,为了保证页的连续性,InnoDB存储引擎每次从磁盘一次申请4-5个区。默认情况下,InnoDB存储引擎的页大小为16KB,即一个区中有64个连续的页。

页(Page)

页是InnoDB存储引擎磁盘管理的最小单位,每个页默认16KB;InnoDB存储引擎从1.2.x版本开始,可以通过参数innodb_page_size将页的大小设置为4K、8K、16K。若设置完成,则所有表中页的大小都为innodb_page_size,不可以再次对其进行修改,除非通过mysqldump导入和导出操作来产生新的库

这块我们分析下为什么连续?

  • mysql的操作都是以页为单位;

  • 连续的空间可以省掉磁盘磁头寻址的时间;

  • 连续的空间也方便零拷贝操作;

  • cpu的高速缓存在查找时效率更高(连续的空间能查找的范围更大)

我们再根据连续索引结构来分析下:

  • 假设我们主键为bigint,占用8字节的存储空间

  • 我们根据存储结构讲的时候的一个公式 132+n(8+27)<16*1024 约460个索引

  • 假设我们一个索引对应一个数据页

  • 假设我们的索引一共2层,第一层就一个数据页 460*460一共有21万数据页

  • 最坏情况下,我们一页存储100条数据,就接近2000万的数据了

  • 那我们在检索的过程通过二分查找,一层最多8次,最多也就16次定位到了对应的数据页,再通过有序链表查,最多116次就能定位到数据;

  • 我们在看下索引的大小 16k(460+1)= 7mb多点

  • 如果这些都在内存中,查询效率可想而知

在之前分享过一篇 记一次生产慢sql查询的解决我们把对应的图拿过来。

  • 聚簇索引直接使用的主键

  • 可以通过主键直接定位到数据

  • 非聚簇索引使用的非主键作为索引

  • 通过索引值和主键的映射最终找到数据

  • 通过主键再去聚簇索引中定位数据,叫回表

大家思考下:

我们怎么去建索引更高效?

为什么字段类型不匹配的时候索引失效?

为什么不建议在查询时使用mysql的函数去过滤列?

部分参考

https://blog.haohtml.com/archives/19232

如果觉得对你有帮助,请关注公众号:5ycode,后续会不断更新哦

公众号图片

Guess you like

Origin blog.csdn.net/f80407515/article/details/119531508