MySql性能(1)—索引结构

索引是帮助mysql高效获取数据的有序数据结构

索引存储在磁盘文件中。

数据表中的数据看上去是连续的,但是是在磁盘随机存储的。所以在查找表中的数据时,操作系统会进行磁道旋转磁头寻道,CPU将数据从硬盘读取到内存中,在与内存进行交互。

若不存在索引的情况下,实际上找数据不是从表从上到下找到数据,而是需要和磁盘发生一次次IO操作。这就是若不使用索引,查询速度比较慢的原因。

索引的存储结构

例如:在表中查询id=8的列,首先CPU会将索引根节点数据读取到内存,然后确定第二层节点的位置。然后在进行一次IO;之后确定第三层节点的位置,在进行一次IO。如果存储结构高度很高的情况下,那么势必会进行多次IO操作。

  • 索引的预读策略

磁盘一般会顺序向后读取一定长度的数据(页的整数倍)放入到内存;

  • 索引的局部性原理

当一个数据被用到时,其附近的数据也通常会马上被用到;

  1. 为什么不是二叉树

但是高度不可控,且若是单调递增,二叉树将退化为链表。

  1. 为什么不是红黑树

插入后树自动调整,可以减少树的高度,但是红黑树高度还是不可控,IO次数还是很多。

  1. 思考下为什么也不是B-树

B-Tree是采用横向树,减少树的高度,从而减少IO的操作。

Mysql5.6之后,可以通过SHOW GLOBAL STATUS like 'Innodb_page_size'。查看mysql文件页大小.

MySql性能(1)—索引结构_第1张图片
查看mysql文件页的大小.png

上图代表的意思是:每个节点的大小一般为16K,即一次IO操作,会将16K的数据读取到内存中。

MySql性能(1)—索引结构_第2张图片
B-Tree的结构.png
  • 一个节点的大小为16K,但16K中即包含索引值和data域(该数据行记录);
  • 叶节点的指针为空;
  • 节点中的数据key从左到右递增排序;

B+Tree(B-Tree变种):mysql的索引结构

B+Tree是B-Tree的改良版本。

  • 非叶子节点不存储data(数据行),只存储key(索引值)。那么非叶子节点可以包含更多的索引值;
  • 叶子节点不存储指针;
  • 叶子节点中包含顺序访问指针,可以提高区间访问的性能。
MySql性能(1)—索引结构_第3张图片
B+Tree结构.png

聚簇索引和非聚簇索引

MyISAM:根据索引确定叶节点,叶节点存储的是文件指针。根据文件指针在进行一次I/O找到相应的记录;
InnoDB:根据索引确定叶节点,叶节点存储的是记录;

B+Tree叶节点若存储的是文件指针,即为非聚簇索引;若B+Tree叶节点存储的是实际记录,即为聚簇索引。

为什么MyISAM会比Innodb的查询速度快?

  1. InnoDB存储的是数据块,而MyISAM值存储索引快,减少了换进换出;
  2. InnoDB寻址映射先到块,再到行,而MyISAM记录的直接是文件地址,定位也比InnoDB速度快;
  3. InnoDB需要维护MVCC一致。

InnoDB索引实现—聚簇索引

  • 表结构文件本身是按照B+Tree组织的一个索引结构文件;
  • 聚餐索引—叶节点包含了完整的数据记录;
MySql性能(1)—索引结构_第4张图片
聚簇索引的结构.png

1. 为什么InnoDB表一定要有主键,且推荐主键使用整型的自增主键?

InnoDB数据本身就是一个B+Tree的索引文件,若不显示指定主键,InnoDB也会默认生成一个主键列;
若不使用自增型的整型主键,若使用UUID:

  • UUID比较长,浪费空间;
  • UUID为字符串,比较速度比较慢;
  • B+Tree是从左到右递增顺序,而UUID生成的随机的,若插入数据所在节点已经存储满的情况下,会导致节点的分裂

联合索引的底层存储结构

MySql性能(1)—索引结构_第5张图片
联合索引的结构.png

图来自《高性能Mysql-第三版》;联合索引 key(last_name,first_name,dob)

B+Tree存储的索引列是有序的!索引对多个值进行排序的依据是CREATE TABLE语句中定义索引时刻的顺序,最后两个节点。两个人姓和名都相同的情况下,则按照出生日期来排列顺序。就像字符串排序时,先按照首字符,若首字符相同情况下,后面字符依次排序

慢sql优化

1. 开启慢sql监控;
2. 抓取到慢sql,使用explain查看执行计划;

使用explain进行分析时,分析结果中有如下几列:

+----+-------------+---------+------+---------------+------+---------+------+------+-------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-------+-------+

  • id:select查询的序列号。
    id相同,执行顺序由上到下;id不同,id值越大优先级越高,越先被执行;
  • select_type:多表连接或子查询时,select的操作类型。
    • simple:表示简单查询,join也是简单查询。(不包含union和子查询)。
    • primary:表示主查询(最外层的查询)。包含union操作的第一个select查询。
    • subquery:表示子查询(子查询中的第一个select查询)。
    • derived:表示导出表,from后跟子查询。
    • union:表示union操作的第2个或后面的查询。
    • union result:表示获取union最后结果的查询。
  • table:查询的表。
  • type:找到匹配行用到的访问类型。
    • 最常见的访问类型是:system、const、eq_ref、ref、range、index、All。
    • system:是const类型的特例,该表里最多只有一条数据;
    • const:最多只有一个匹配行,例如主键的primary key或唯一索引unique index进行查询;
    • eq_ref:使用唯一索引,对于每个索引键值,表中只有一条数据匹配,简单来说,就是多表连接中使用primary key或unique index作为关联条件;
    • ref:使用非唯一索引,或唯一索引的前缀扫描;
    • range:只检索指定范围的行,使用一个索引来选择行,常见于范围查找。
    • index:索引全扫描,遍历整个索引来查询匹配的行;
    • ALL:全表扫描,性能最差;
  • possible_keys:表示查询时可能用到的索引。
  • key:表示实际用到的索引。
  • key_len:使用到索引字段的长度。
  • rows:扫描行的数量。
  • Extra[埃克斯抓]:执行情况的说明和描述。

3. 使用show profile分析sql

有时候仅仅通过explain分析执行计划并不能很快的定位到sql的问题,这时就可以选择
show profile联合分析(用来分析当前会话sql语句执行的资源消耗情况的工具)。
MySQL高级知识(十一)——Show Profile

-- 查看profile功能是否开启
show VARIABLES like 'profiling';
-- 执行目标sql
select * from user_t
-- 获取到该会话的sql执行的资源损耗
show profiles;
-- 展示该sql各阶段的耗时
show profile cpu,block io,memory for QUERY 25;

show profiles是在mysql5.0.37之后添加。设置show profiles后,后续执行的sql语句都将记录其资源开销,诸如IO/上下文切换/CPU/MEMOYR等等。

MySql性能(1)—索引结构_第6张图片
记录的时间开销.png

推荐阅读

MySQL索引背后的数据结构及算法原理

慢查询优化

历史文章

mybatis&&数据库优化&&缓存目录

你可能感兴趣的:(MySql性能(1)—索引结构)