文章目录
- 3.MySQL索引及两种索引分类方法
- 3.1索引的概念
- 3.1.1相关定义
- 3.1.2查询例子
- 3.2索引的底层
- 3.2.1二叉树
- (1)满二叉树
- (2)完全二叉树
- (3)二叉查找树
- (4)二叉平衡树(AVL)
- ①区分深度和高度
- ②平衡因子
- ③特点
- (5)红黑树(BST)
- 3.2.2B树
- 3.2.3B+树
- 3.3索引的类型
- 3.3.1按功能逻辑区分
- (1)主键索引——Primary key(column)
- (2)唯一索引——Unique(column)
- (3)普通索引——Index index_name(column)
- (4)全文索引——Fulltext(column)
- (5)前缀索引——Key(column_name(prefix_length))
- (6)组合索引——Index index_name(column1,column2)
- (7)空间索引
- 3.3.2按底层数据结构区分
- (1)聚簇索引&&非聚簇索引(二级索引)
- 3.3.3InnDB存储引擎的两种索引
- (1)InnoDB——主键索引(聚簇索引)
- (2)InnDO——辅助索引(非聚簇索引(二级索引))
- (3)主键搜索过程
- 3.3.4MyISAM的索引
- (1)MyISAM——主键索引(非聚簇索引)
- (2)MyISAM-辅助索引(非聚簇索引)
- 3.4相关概念(回表/索引覆盖/索引下推)
- 3.4.1回表
- 3.4.2索引覆盖
- 3.4.3索引下推
- 3.5参考文章链接
- 3.6总结
3.MySQL索引及两种索引分类方法
3.1索引的概念
3.1.1相关定义
- 索引(在MySQL中也叫做“键(key)”)是存储引擎用于快速找到记录的一种数据结构,这也是索引最基本的功能。
- 索引优化是查询性能优化最有效的手段。
- 如果想要在一本书中找到某个特定主题,一般会先看书的目录,找到对应的页码,然后直接翻到对应的页码即可查看。在MySQL中,存储引擎用类似的方法使用索引,首先在索引中找到对应的值,然后根据匹配的索引记录找到对应的数据行。简单的说,数据库索引类似于书前面的目录,能加快数据库的查询速度。
3.1.2查询例子
select name from user where user_id = 5
- 如果user_id列上建有索引,则MySQL将使用该索引找到user_id 为 5的行,即MySQL现在索引上按值进行查找,然后返回包含该值的数据行。
- 索引可以一个或多个列的值,如果索引包含多个列,那么列的顺序也很重要,因为MySQL只能高效地使用最左前缀列。
3.2索引的底层
- MySQL默认使用的索引的底层数据结构是 B+树
- 以下将介绍二叉树、满二叉树、完全二叉树、二叉查找树、二叉平衡树(AVL)、红黑树(BST)
- B树、B+树
3.2.1二叉树
- 特点:每个节点最多有两个子树的树结构
(1)满二叉树
- 特点:除了叶子节点外,每一个节点都有两个子节点,且所有叶子节点都在二叉树的同一高度上
(2)完全二叉树
- 特点:完全二叉树 除去底层节点后为满二叉树,且底层节点依次从左到右分布
(3)二叉查找树
- 特点:任意一个节点的值大于左子树任意一个节点的值,小于右子树任意一个节点的值
(4)二叉平衡树(AVL)
①区分深度和高度
-
深度
- 根节点深度为0
- 从根节点自顶向下逐层累加
-
高度
- 叶子节点高度为0
- 从叶子节点自底向上逐层累加
②平衡因子
- 平衡因子:该节点的左子树深度-右子树深度
③特点
特点:树中任一节点的两个子树的平衡因子的绝对值不超过1(重要)
(5)红黑树(BST)
-
红黑树是一棵自平衡搜索树
-
规则
- 根节点总是黑色
- 每个节点只能是红色或黑色
- 红色节点的父或子节点必然是黑色的(即两个红色的节点不会相连)
- 任意节点到后代NULL节点的每条路径都具有相同数量的黑色节点
- 每个NULL节点都是黑色的
-
如何保证平衡
- 左旋/右旋
- 左旋:根节点往左偏转,将右子树的第一个节点变成根节点
- 右旋:根节点往右偏转,将左子树的第一个节点变成根节点
- 染色:更改根子节点的颜色,确保满足规则
- 左旋/右旋
3.2.2B树
- B树即一棵多(m)路平衡查找树
- 字母m表示阶数,一个结点最多有多少个孩子结点,同时m必须>2
- 一个结点中同时存储关键字、以及指向儿子节点的指针
- 特点:
- 关键字数据分布在整棵树中,即数据均分布在树中
- 任何一个关键字仅且出现在一个节点中
3.2.3B+树
- 基于B树进行改造的树,更适合海量数据的存储
- 特点
- 所有关键字均分布在叶子节点的链表中
- 非叶子节点不存储关键字,只存储key以及指向儿子节点的指针
- 叶子节点之间互相串联,首尾相连
- 与B树对比:
- 磁盘读写代价更低
- 查询效率更稳定
- 更便于扫库和区间扫描
3.3索引的类型
3.3.1按功能逻辑区分
(1)主键索引——Primary key(column)
-
定义:数据列不允许重复,不允许为NULL,一个表只能有一个主键
-
举例:
ALTER TABLE table_name ADD PRIMARY KEY (column);
(2)唯一索引——Unique(column)
-
定义:索引列中的值必须是唯一的,但是允许NULL值。建立唯一索引的目的大部分时候都是为了该属性列的数据的唯一性,而不是为了查询效率。一个表允许多个列创建唯一索引。
-
举例:
ALTER TABLE table_name ADD UNIQUE (column);
(3)普通索引——Index index_name(column)
-
定义:MySQL中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和NULL值。一个表允许多个列创建普通索引
-
举例:
ALTER TABLE table_name ADD INDEX index_name (column);
(4)全文索引——Fulltext(column)
-
定义:主要是为了快速检索大文本数据中的关键字的信息。字段长度比较大时,如果创建普通索引,在进行like模糊查询时效率比较低,这时可以创建全文索引,基于倒排索引,类似于搜索引擎。MyISAM存储引擎支持全文索引,InnoDB 存储引擎在 MySQL 5.6.4 版本中也开始支持全文索引
-
举例:
ALTER TABLE table_name ADD FULLTEXT (column);
(5)前缀索引——Key(column_name(prefix_length))
-
定义:在文本类型如BLOB、TEXT或者很长的VARCHAR列上创建索引时,可以使用前缀索引,数据量相比普通索引更小,可以指定索引列的长度,但是数值类型不能指定。
-
举例:
ALTER TABLE table_name ADD KEY(column_name(prefix_length));
(6)组合索引——Index index_name(column1,column2)
-
定义:指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用组合索引时遵循最左前缀原则。
-
主键索引、普通索引、唯一索引等都可以使用多个字段形成组合索引
-
举例:
ALTER TABLE table_name ADD INDEX index_name ( column1, column2, column3 )
(7)空间索引
- 定义:MySQL在5.7之后的版本支持了空间索引,而且支持OpenGIS几何数据模型。MySQL在空间索引这方面遵循OpenGIS几何数据模型规则。
3.3.2按底层数据结构区分
在前面已经介绍过了MySQL索引默认的底层数据结构为B+树,还要以下相关索引的特点
- 它是一棵 B+Tree
- 每一个 B+Tree 的节点都是一个「数据页」
- 索引是在存储引擎层实现的,所以并没有统一的索引标准,即不同存储引擎的索引的工作方式并不一样
(1)聚簇索引&&非聚簇索引(二级索引)
- 聚簇索引:
- 将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据(所有字段的值)。
- 有且仅有一个
- 规则
- 依次选择主键索引、唯一索引作为聚簇索引
- InnoDB自动生成一个rowid作为隐藏的聚簇索引
- 非聚簇索引:
- 将数据与索引分开存储,索引结构的叶子节点指向了数据对应的位置
- 可以存在多个
3.3.3InnDB存储引擎的两种索引
在InnoDB存储引擎中,主键索引和辅助索引的索引类型分别为聚簇索引和非聚簇索引
(1)InnoDB——主键索引(聚簇索引)
(2)InnDO——辅助索引(非聚簇索引(二级索引))
(3)主键搜索过程
整个查询的过程如下:
- 查询 id(主键) 为 18 的数据,SELECT id, name, age WHERE id = 18。
- 首先在「根节点:节点一」上,id = 18 落在了 15 <= id < 56 范围之内,这样我们就知道了下级节点「非叶子节点:节点2-1」的地址。
- 根据【步骤2】得到的「非叶子节点:节点2-1」的地址,找到对应的「非叶子节点:节点2-1」。然后,id = 18 又落在了 15 <= id < 20 范围之内,这样我们就知道了再下一级节点「叶子节点:节点3-1」的地址。
- 根据【步骤3】得到的「叶子节点:节点3-1」的地址,找到对应的「叶子节点:节点3-1」。最后,在「叶子节点:节点3-1」这个节点上找到 id = 18 对应的数据 {“id”: 18, “name”: “King”, “age”: 17}
3.3.4MyISAM的索引
- 在存储引擎为 MyISAM 的表中,主键索引和辅助索引的类型都是非聚簇索引。
- 两棵 B+Tree 的结构完全一致,只是存储的内容不同
- 主键索引 B+Tree 的节点存储了 「主键」+「数据记录的地址」
- 辅助键索引 B+Tree 存储了 「索引列的值」+「数据记录的地址」。
- 还有一点不同是主键索引中的 key 必须是唯一的,而辅助索引中的 key 可以重复。
(1)MyISAM——主键索引(非聚簇索引)
(2)MyISAM-辅助索引(非聚簇索引)
3.4相关概念(回表/索引覆盖/索引下推)
3.4.1回表
- 定义:通过二级索引找到对应的主键值,再到聚簇索引中查找整行数据的过程
主要发生在通过辅助索引查询的时候,通过辅助索引找到 B+Tree 中的叶子结点,但是辅助索引的叶子节点内存储的数据不全,只有索引列的值和主键值。我们还需要拿着刚从辅助索引中得到的主键值再去聚簇索引(主键索引)的叶子节点中去拿到完整的数据(全部字段),这个过程就叫「回表」。
3.4.2索引覆盖
-
定义:指第一次使用了索引,并且找到了全部所有需要返回的数据
-
例子:
- 使用id查询,直接使用聚簇索引,返回数据
- 如果返回的列,在索引存储的数据没有找到,就会触发回表查询
-
结论:避免使用select *
-
应用:解决MySQL超大分页
-
原:
select * from tb_sku limit 900000,10
-
改:通过子查询+覆盖索引解决:在子查询中,先通过按 id 排序选择第 9000000 到第 9000009 行的数据,并拿到id,再通过id,由覆盖索引查到详细数据
select * from tb_sku t,(select id from tb_sku order by id limit 9000000,10) a where t.id=a
-
3.4.3索引下推
索引下推,严格来说应该叫「索引条件下推」。该功能是 MySQL 数据库 5.6 版本添加的,用于优化数据查询,默认情况处于开启状态。我们可以通过如下命令来开启和关闭「索引条件下推」功能:
- 开启
SET optimizer_switch = 'index_condition_pushdown=on'
- 关闭
SET optimizer_switch = 'index_condition_pushdown=off'
下面通过一个例子来说下什么是「索引条件下推」,首先我们假设有这么一张表:
- 表名:t_user
- 字段:id,name,mobile
- 辅助索引:name + mobile(索引名:name_mobile_normal)
表结构如下:
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
`name` varchar(100) COLLATE utf8_bin NOT NULL COMMENT '姓名',
`mobile` varchar(200) COLLATE utf8_bin NOT NULL COMMENT '手机',
PRIMARY KEY (`id`) USING BTREE,
KEY `name_mobile_normal` (`name`,`mobile`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='用户表';
下面,让我们来分别看下关闭和开启「索引条件下推」这两种情况,下边这个查询语句的执行计划有怎样的不同。
EXPLAIN SELECT * FROM t_user WHERE name = 'A' AND mobile LIKE '%138'
-
关闭「索引条件下推」
-
开启「索引条件下推」
-
从上边,我们可以看到,关闭「索引条件下推」时候 Extra 是 Using where;开启「索引条件下推」时候 Extra 是 Using index condition。
当关闭「索引条件下推」的时候,MySQL 首先通过索引将匹配 name = ‘A’ 的数据都查出来(在存储引擎中完成),然后再从这些数据中找到与 mobile LIKE ‘%138’ 条件相匹配的数据(在 Server 层完成)。
当开启「索引条件下推」的时候,因为 name 和 mobile 对应的值已经都存储在索引中了(也就是说我们可以直接拿到这个值,来判断数据是否与查询条件匹配),这样就可以直接在存储引擎中完成数据的查询了。
综上所述,索引条件下推就是 “过滤的动作 尽量由 下层的存储引擎层 通过 使用索引 来完成,而不需要上推到 Server 层进行处理” ,实现的主要思路是充分利用索引中存储的数据,尽量把根据条件过滤数据的操作交给存储引擎来做(这样可以最大限度的减少需要「回表」的数据)。
最后,还需要注意的是由于该技术基于存储引擎,只有特定的存储引擎可以使用。而且,条件判断操作必须可以在存储引擎运行,比如调用存储过程的条件就不可以,因为存储引擎没有调用存储过程的能力。
3.5参考文章链接
- MySQL中的 索引、聚簇索引、非聚簇索引、回表、索引覆盖、索引下推 都是啥?
3.6总结
MySQL系列第三篇主要介绍了MySQL索引的定义,深入理解索引的底层数据结果(B+树),还介绍了其他树的特点,最后按功能逻辑和按底层数据结构两种分类方法将索引分别分类,其中重点为聚簇索引和非聚簇索引,我们需要理解并记住两种索引的区别,最后最后介绍了InnoDB和MyiSAM两种引擎下,主键索引和辅助索引对应聚簇索引还是非聚簇索引,还介绍了回表查询、覆盖索引、以及索引下推等相关概念