索引是帮助mysql高效获取数据的有序数据结构
;
索引存储在磁盘文件中。
数据表中的数据看上去是连续的,但是是在磁盘随机存储的。所以在查找表中的数据时,操作系统会进行磁道旋转
与磁头寻道
,CPU将数据从硬盘读取到内存中,在与内存进行交互。
若不存在索引的情况下,实际上找数据不是从表从上到下找到数据,而是需要和磁盘发生一次次IO操作。这就是若不使用索引,查询速度比较慢的原因。
索引的存储结构
例如:在表中查询id=8的列,首先CPU会将索引根节点数据读取到内存,然后确定第二层节点的位置。然后在进行一次IO;之后确定第三层节点的位置,在进行一次IO。如果存储结构高度很高的情况下,那么势必会进行多次IO操作。
- 索引的预读策略
磁盘一般会顺序向后读取一定长度的数据(页的整数倍)放入到内存;
- 索引的局部性原理
当一个数据被用到时,其附近的数据也通常会马上被用到;
但是高度不可控,且若是单调递增,二叉树将退化为链表。
插入后树自动调整,可以减少树的高度,但是红黑树高度还是不可控,IO次数还是很多。
B-Tree是采用横向树,减少树的高度,从而减少IO的操作。
在Mysql5.6
之后,可以通过SHOW GLOBAL STATUS like 'Innodb_page_size'。
查看mysql文件页大小.
上图代表的意思是:每个节点的大小一般为16K,即一次IO操作,会将16K的数据读取到内存中。
- 一个节点的大小为16K,但16K中即包含索引值和data域(该数据行记录);
- 叶节点的指针为空;
- 节点中的数据key从左到右递增排序;
B+Tree是B-Tree的改良版本。
- 非叶子节点不存储data(数据行),只存储key(索引值)。那么非叶子节点可以包含更多的索引值;
- 叶子节点不存储指针;
- 叶子节点中包含顺序访问指针,可以提高区间访问的性能。
聚簇索引和非聚簇索引
MyISAM:根据索引确定叶节点,叶节点存储的是文件指针。根据文件指针在进行一次I/O找到相应的记录;
InnoDB:根据索引确定叶节点,叶节点存储的是记录;
B+Tree叶节点若存储的是文件指针,即为非聚簇索引;若B+Tree叶节点存储的是实际记录,即为聚簇索引。
- InnoDB存储的是数据块,而MyISAM值存储索引快,减少了换进换出;
- InnoDB寻址映射先到块,再到行,而MyISAM记录的直接是文件地址,定位也比InnoDB速度快;
- InnoDB需要维护MVCC一致。
- 表结构文件本身是按照B+Tree组织的一个索引结构文件;
- 聚餐索引—叶节点包含了完整的数据记录;
1. 为什么InnoDB表一定要有主键,且推荐主键使用整型的自增主键?
InnoDB数据本身就是一个B+Tree的索引文件,若不显示指定主键,InnoDB也会默认生成一个主键列;
若不使用自增型的整型主键,若使用UUID:
- UUID比较长,浪费空间;
- UUID为字符串,比较速度比较慢;
-
B+Tree是从左到右递增顺序
,而UUID生成的随机
的,若插入数据所在节点已经存储满的情况下,会导致节点的分裂
;
联合索引的底层存储结构
图来自《高性能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等等。
推荐阅读
历史文章
mybatis&&数据库优化&&缓存目录