Mysql 索引存储原理

前言

好像每次面试,面试官都会问到数据库,从而问到数据库的存储引擎、索引,以及它们对比起来的区别,今天来讲讲 Mysql 的索引。

索引:

索引是帮助 Mysql 高效获取数据的 排好序 数据结构
(这句话是MySQL官方对索引的定义)

附赠一个地址,上面可以演示很多数据结构添加链接描述

在这里插入图片描述

索引的数据结构

  • 二叉树:左小右大存放
    弊端:假设数据一直递增,那么数据也会一边倒,那么假设查找6这个数字,也是会查找6次
    在这里插入图片描述

  • 红黑树:红黑树也叫平衡二叉树,在二叉树的基础上做了一个平衡,它不会让数据在插入的时候出现一边倒
    弊端:数据在很大的时候,“树高”还是很高,会让查询的速度变慢
    在这里插入图片描述

  • Hash 表:对索引的key 进行一次 hash 计算就可以定位出数据存储的位置,很多时候 Hash 索引要比 B+Tree 索引更高效(算出相同的数据存储位置,就会发生 Hash 碰撞)
    弊端:仅能满足 “=”,“IN”,不支持范围查询。还有 Hash 冲突
    在这里插入图片描述

  • B-Tree
    在这里插入图片描述

  • B+Tree(B-Tree的变种):

  1. 非也节点不存储 data,只存储索引(索引是冗余的),这样就可以放更多的索引。
  2. 叶子节点包含所有的索引字段
  3. 叶子节点用 指针 连接,提高区间访问的性能

Mysql底层就是用的 B+Tree 存储数据的

计算三层高的B+Tree 能保存多大的数据

主键索引维护整张表的情况下…

  1. Mysql 保证了一个叶子节点的大小在 16KB
  2. 一个 Bigint 的大小是 8 byte
  3. 一个索引,旁边附带一个子节点的磁盘地址指针(空白部分),空白磁盘指针分配了 6 byte ,一共是16 byte。 所以第一层子节点能放约 1170 个索引元素
  4. 同理第二层也是 1170 个索引元素
  5. 第三层叶子节点上面放的是 索引元素+数据,大约估计 1KB, 索引第三层一个节点有 16 个
  6. 一共是: 1170 1170 16 = 2 千多万

数据库存储引擎

Mysql 存储引擎有9个,但常用的是 InnerDB、MyISAM。

今天主要是说索引,就不对比两种存储引擎的区别。对比一下不同引擎对应的索引是底层是如何存储数据的,以及它们的区别

存储引擎是修饰表的,这一点需要大家知道

MyISAM

MyIASM 索引文件和数据文件是分离的(非聚集)

在底层,它每张表都会生成有三个文件:

  • .frm 文件:存储表结构
  • .MYD 文件:存储表数据
  • .MYI 文件:存储表索引

在这里插入图片描述
与 InnerDB 不同,它叶子节点保存的不是数据本身了,是数据所在的 磁盘文件地址,然后它再拿着这个文件地址,去找该行数据

InnerDB

InnerDB的索引文件和数据是放在一起的(聚集)

  • .frm 文件:保存表结构
  • .ibd 文件:保存数据和索引

与 MyISAM 不同,它叶子节点保存是数据本身,这就是本质区别 。

从数据结构出发, InnerDB 存储引擎查找数据要比 MyISAM 要快,因为前者只会经历 1 次磁盘的 IO,后者需要拿着磁盘地址找数据,会经历 2 次 磁盘 IO

B+Tree 与 B-Tree 的对比分析(蚂蚁金服一面)

  1. B-Tree 叶子节点没有双向指针,在范围查询的时候不是很友好的
  2. B+Tree 数据都挪到了叶子节点,非叶子节点的上面的索引是重复的。而B-Tree 非叶子节点上面有数据,非叶子节点上面的索引不重复。
    B+Tree 把数据挪到叶子节点上的原因:是为了让你的非叶子在同样数据大小的情况下,横向能存储更多的索引,树越低,查询速度就越快

联合索引的底层存储结构分析

用 name、age、position 维护一个联合索引:
在这里插入图片描述

CREATE TABLE `employee` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(24) CHARACTER SET latin1 NOT NULL COMMENT '姓名',
  `age` INT(11) UNSIGNED ZEROFILL NOT NULL COMMENT '年龄',
  `position` VARCHAR(20) CHARACTER SET latin1 NOT NULL COMMENT '只为',
  `hire_time` DATETIME DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '入职时间',
  PRIMARY KEY (`id`),
  KEY `idx_name_age_position` (`name`,`age`,`position`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf-8 COMMENT="员工记录"

INSERT INTO employee(NAME,age,POSITION,hire_time) VALUES("lilei",22,"manager",NOW())
INSERT INTO employee(NAME,age,POSITION,hire_time) VALUES("zhangsan",25,"dev",NOW())

下面有三条sql语句,看看那几条会走这个索引?

EXPLAIN SELECT * FROM employee WHERE name="Bill" and age=21;
EXPLAIN SELECT * FROM employee WHERE age=30 and position="dev";
EXPLAIN SELECT * FROM employee WHERE position="manager";

执行结果

Result1:
在这里插入图片描述
Result2:
在这里插入图片描述
Result3:
在这里插入图片描述
显然只有 第一条 sql 语句才走到了索引。第二个,第三个sql 跳过了 name ,所以没走到索引。这就是联合索引的 最左匹配原则

最左匹配原则
只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用复合索引时遵循最左前缀集合,所以在建立联合索引的时候查询最频繁的条件要放在左边

猜你喜欢

转载自blog.csdn.net/weixin_43582499/article/details/113740431
今日推荐