前言:本文是自己的阅读《Mysql技术内幕——InnoDB存储引擎》的笔记,主要是为了将阅读和实践结合起来,途中会穿插自己的理解及自己工作中的实践。我理解阅读一本经典的书,无论是技术书籍还是生活数据,带着目的去读,知道书讲得是什么,并且结合自己的理解,输出一定的文字。
经常在工作中,会遇到某个查询比较慢的时候,小伙伴就会思考是否需要新增一个索引来解决呢?
慢 ——> 索引 ——> 解决
似乎索引是一种能够提高速度的东东,那么到底是什么呢?本文带领你一探究竟。
InnoDB存储引擎支持的索引主要有:
可能有人就会问,什么是B+树索引呢?其内部主要结构是什么样的呢?
B+树的数据结构整体属于:
数据存放到叶子节点中,非叶子节点只存放相应的索引。
同时B+树的高度十分稳定,一般高度都是2 - 4层,这样的话,每次查询最多只需要进行2到4次的磁盘IO。
什么是聚集索引?
按照每张表的主键构造一颗B+树,同时叶子节点中存放的是整张表的行记录数据,叶节点的数据页通过双向链表进行连接。
而非聚集索引中,存放的仅仅是键值及其指向数据页的偏移量。
聚集索引的好处?
对于主键的排序查找和范围查找速度很快。因为叶子节点存放的数据就是用户所需要查询的数据。
辅助索引又称为非聚集索引。叶子节点并不包含行记录的全部数据,包含的是键值及对应的数据页偏移量,该偏移量用于判断去哪儿可以找到与索引相对应的行数据。
一般查找过程:通过非聚集索引中的偏向量,找到对应的主键索引的主键,在通过主键索引找到一个完整的行记录。这通常又称为回表查询
记住:Innodb存储引擎是一个索引组织表
1、如何创建和管理索引
创建索引的方式有两种,第一种是建表的时候,第二种是后续修改。
ALTER TABLE t ADD KEY ind_id (id);
可以通过如下命令查看表中的索引
SHOW INDEX FROM t\G;
字段 | 含义 |
---|---|
Table | 索引所在表名 |
Non_unique | 非唯一索引 |
Key_name | 索引名字 |
Seq_in_index | 索引中该列的位置 |
Column_name | 索引所在表名 |
Collation | 列以什么方式存储在索引中,A表示排序, |
Cardinality | 索引中唯一值的数目的估计值,这个值很关键,会根据该值判断是否使用索引 |
Sub_part | 是否是列的部分为索引 |
Packed | 关键字的压缩方式 |
Null | 索引的列是否包含Null值 |
Index_type | 索引的类型 |
前面说到了Cardinality对于索引分析十分关键,那么什么是cardinality呢?
这个值主要用于判断某个索引是否真的有用,一般建立索引的原则是:某个字段的取值范围很广,基本上没有重复。则适合于建立B+数索引。
Cardinality值就是用来判断字段是否符合这个特征,因为该值的定义是:不重复记录数据的条数。
可以想一下,如何统计该值呢?
总不可能每次有变化,则将整个表整体计算一遍吧,那样如果数据量超级大的情况下,服务器性能都被计算Cardinality吃掉了,势必会导致insert和update很慢。Innodb采用的是随机抽象的方法。
什么是联合索引?
对表中的多个列进行索引,组成一个组合索引。
联合索引在B+树的排列顺序是按照建立索引的顺序排列的,也就是最左原则。
比如建立一个订单表:
CREATE TABLE `orders` (
`order_num` int(11) NOT NULL AUTO_INCREMENT COMMENT '订单号',
`order_date` datetime NOT NULL COMMENT '订单日期',
`cust_id` int(11) NOT NULL COMMENT '用户Id',
`shop_id` int(11) DEFAULT NULL COMMENT '店铺Id',
PRIMARY KEY (`order_num`),
KEY `ind_orderNum_date` (`order_num`,`order_date`)
) ENGINE=InnoDB AUTO_INCREMENT=20022 DEFAULT CHARSET=utf8;
组合索引ind_orderNum_date
在B+树中是先按照order_num,再按照order_date排序。
因此如下查找是没有办法利用索引的
select * from orders where order_date = '2020-06-07 00:00:00'
下面可以看一下组合索引在B+树中的结构
基本上是一种组合排序的形式,从索引左边元素往右边元素依次排序,当然下面的图只是一个例子
什么是覆盖索引?
从辅助索引中就可以得到查询的结果,而不需要再根据辅助索引的key及指针查询聚集索引的记录。
覆盖索引的好处?
查找数据快,并且辅助索引不包含整行记录的所有信息,因此物理大小 小于聚集索引,可以减少大量的IO操作。
并且对于统计性问题,比如求解count()
之类的
explain select count(*) from orders where order_date>= '2005-09-30 00:00:00';
按照索引的最左原则,按道理是无法利用到ind_orderNum_date
索引的,但是分析发现:
并且看explain结果中Extra是Using Index,这就代表利用了覆盖索引。
比如下面的查询
explain select * from orders where order_num>= '20046' and order_num <= '20058';
系统分析可能使用的索引有PRIMARY
、 ind_orderNum_date
,系统最后选择了使用PRIMARY
,这种方式其实就是一种表扫描的方式。因为用户想要的是全列的数据,无法利用上其他索引。
Multi-Range Read
优化,又简称为MRR
。
那么什么是MRR优化呢?
主要目的是减少磁盘的随机访问,并且将随机访问转化为较为顺序的数据访问。执行计划会自己帮助分析如何进行MRR
优化。会自己将范围查询拆分为键值对的查询。
主要使用的查询类型:
type为range、red、eq_ref类型的查询
有哪些好处?
Index Condition PushDown 优化同样是Msyql5.6开始支持的一种根据索引进行查询的优化方式。
为什么需要ICP?
在此之前的做法是:当进行索引查询时,先根据索引来查找记录,然后再根据where条件过滤记录。
ICP优化之后:Mysql会在取出索引的同时,判断是否可以进行WHERE条件的过滤。有时可以减少上层SQL对记录的拉取,提高数据库整体性能。(如果不满足条件了,则不拉取数据了)
使用哪些查询情况?
主要支持range、ref、eq_ref、ref_or_null类型的查询
Innodb采用自适应hash索引,系统自己创建并使用,用户无法自己创建。
本文主要讲解了索引的一些基础知识,包括各个索引的区别及底层B+树的结构等,需要对于新版本中的索引的优化加一些注意比如MRR优化,ICP优化等。