十四、深入理解Mysql索引底层数据结构与算法

embedded/2024/10/18 18:29:15/

文章目录

  • 一、索引的本质
    • 1、索引是帮助MySQL高效获取数据的排好序的数据结构
    • 2、索引的数据结构
    • 3、数据结构可视化网站
  • 二、常见数据结构介绍
    • 1、B-Tree
    • 2、B+Tree(B-Tree变种)
    • 3、Hash结构
  • 三、存储引擎的索引实现
    • 1、MyISAM存储引擎索引实现
      • MyISAM索引文件和数据文件是分离的(非聚集)。
    • 2、InnoDB存储引擎索引实现
      • InnoDB索引实现(聚集):
  • 四、联合索引
    • 1、联合索引案例使用的脚本
    • 2、索引最左前缀原理
    • 3、关于最左前缀的补充
      • 索引跳跃扫描(Index Skip Scan)
      • 索引跳跃扫描优化原理
      • 生效的限制条件

一、索引的本质

1、索引是帮助MySQL高效获取数据的排好序的数据结构

在这里插入图片描述

2、索引的数据结构

  • 二叉树
  • B-Tree
  • Hash表
  • 红黑树

3、数据结构可视化网站

为了更好的了解数据结构,直观的感受数据结构的变化,可以使用如下网站,进行可视化操作。
https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

二、常见数据结构介绍

1、B-Tree

  • 叶节点具有相同的深度,叶节点的指针为空。
  • 所有索引元素不重复。
  • 节点中的数据索引从左到右递增排列。
    在这里插入图片描述

2、B+Tree(B-Tree变种)

  • 非叶子节点不存储data,只存储索引(冗余),可以放更多的索引。
  • 叶子节点包含所有索引字段。
  • 叶子节点用指针连接,提高区间访问的性能。
    在这里插入图片描述

3、Hash结构

  • 对索引的key进行一次hash计算就可以定位出数据存储的位置。
  • 很多时候Hash索引要比B+ 树索引更高效。
  • 仅能满足 “=”,“IN”,不支持范围查询。
  • hash冲突问题。
    在这里插入图片描述

三、存储引擎的索引实现

1、MyISAM存储引擎索引实现

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

在这里插入图片描述

2、InnoDB存储引擎索引实现

InnoDB索引实现(聚集):

  • 表数据文件本身就是按B+Tree组织的一个索引结构文件
  • 聚集索引-叶节点包含了完整的数据记录
  • 为什么建议InnoDB表必须建主键,并且推荐使用整型的自增主键?(方便排序提升查找效率)
  • 为什么非主键索引结构叶子节点存储的是主键值?(一致性和节省存储空间)

四、联合索引

1、联合索引案例使用的脚本

CREATE TABLE `employees` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名',`age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄',`position` varchar(20) NOT NULL DEFAULT '' COMMENT '职位',`hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入职时间',PRIMARY KEY (`id`),KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='员工记录表';INSERT INTO employees(name,age,position,hire_time) VALUES('LiLei',22,'manager',NOW());
INSERT INTO employees(name,age,position,hire_time) VALUES('HanMeimei', 23,'dev',NOW());
INSERT INTO employees(name,age,position,hire_time) VALUES('Lucy',23,'dev',NOW());EXPLAIN SELECT * FROM employees WHERE name = 'Bill' and age = 31;
EXPLAIN SELECT * FROM employees WHERE age = 30 AND position = 'dev';
EXPLAIN SELECT * FROM employees WHERE position = 'manager';

2、索引最左前缀原理

在联合索引中,索引的数据结构如下,正常的索引是遵循B+树结构,索引项从左到右,从小到大排序,假设我们跳过name,直接使用联合索引中的ageposition,由于在比较中,无法先确认第一项name,故无法对整个索引项进行排序,从而导致联合索引失效。
简单理解,其实索引的最左前缀原理就是根据索引中开始的索引字段,按顺序进行匹配排序,实现通过索引的高效查找的的一种规则。
在这里插入图片描述

3、关于最左前缀的补充

索引跳跃扫描(Index Skip Scan)

MySQL一定是遵循最左前缀匹配的,这句话在mysql8以前是正确的,没有任何毛病。但是在MySQL 8.0中,就不一定了。

参考:https://dev.mysql.com/doc/refman/8.0/en/range-optimization.html#range-access-skip-scan

官网示例

CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL, PRIMARY KEY(f1, f2));
INSERT INTO t1 VALUES
(1,1), (1,2), (1,3), (1,4), (1,5),
(2,1), (2,2), (2,3), (2,4), (2,5);
INSERT INTO t1 SELECT f1, f2 + 5 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 10 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 20 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 40 FROM t1;
ANALYZE TABLE t1;EXPLAIN SELECT f1, f2 FROM t1 WHERE f2 > 40;

在这里插入图片描述
虽然我们的SQL中,没有遵循最左前缀原则,只使用了f2作为查询条件,但是经过MySQL 8.0的优化以后,还是通过索引跳跃扫描的方式用到了索引了。

索引跳跃扫描优化原理

mysql8.013后通过优化器帮我们加了联合索引,SQL执行过程如下:

  1. 获取 f1 字段第一个唯一值,也就是 f1 = 1
  2. 构造 f1 = 1 and f2 > 40,进行范围查询
  3. 获取 f1字段第二个唯一值,也就是 f1 = 2
  4. 构造 f1 = 2 and f2 > 40,进行范围查询
SELECT f1, f2 FROM t1 WHERE f2 > 40;-- 执行的最终SQL:
SELECT f1, f2 FROM t1 WHERE f1 =1 and f2 > 40
UNION
SELECT f1, f2 FROM t1 WHERE f1 =2 and f2 > 40;

所以对于f1值很少,区分度不高的情况索引跳跃扫描会快一些;反之查询效率慢些。
我们不能依赖这个优化,建立索引的时候,还是优先把区分度高的,查询频繁的字段放到联合索引的左边。

生效的限制条件

  • 查询必须只能依赖一张表,不能多表JOIN。
  • 查询中不能使用 GROUP BY 或 DISTINCT 语句。
  • 查询的字段必须是索引中的列。
  • 组合索引形式:([A_1, …, A_k,] B_1, …, B_m, C [, D_1, …, D_n]),A,D 可以为空,但是B ,C 不能为空。

http://www.ppmy.cn/embedded/124210.html

相关文章

废品回收小程序/环保垃圾回收/收二手垃圾小程序/分类资源回收系统/独立版系统源码

>>>系统简述: 1.以微信小程序为基础进行开发,体验好,操作方便 2.从用户下单到回收员接单,在到回收站接收,在到代理全流程通过手机端管理 3.支持废品分类下单,并支持分类数据统计 4.独创回收员多个…

[OS] 3.Insert and Remove Kernel Module

Insert and Remove Kernel Module 1. 切换到 root 账户 $ sudo su作用:Linux 内核模块的加载和卸载需要超级用户权限,因此你必须以 root 用户身份进行操作。sudo su 命令允许你从普通用户切换到 root 账户,从而获得系统的最高权限&#xff…

C语言+电焊

啊啊啊&#xff0c;今天又是快乐的一天&#xff01;祝大家节日快乐 C语言 今天也是把丢失的C语言拾起来了&#xff0c;做了一下习题回顾 3.偶数和&#xff08;for循环if条件&#xff09; 注意for/if一类的判断语句后面添加分号会自动忽略语句 for(int i1;i<22;i); {if(i…

【Python】Python知识总结浅析

Python是一种高级编程语言&#xff0c;由Guido van Rossum于1991年首次发布。它以简洁的语法和强大的功能著称&#xff0c;适用于多种应用场景&#xff0c;包括Web开发、数据分析、人工智能、自动化脚本等。 易于学习和使用&#xff1a;Python的语法简洁明了&#xff0c;适合初…

zy91_C#中StringBuilder类以及char类

文章目录 1.StringBuilder类1.1程序代码 2.char类2.1程序代码 1.StringBuilder类 1.1程序代码 static void Main(string[] args) {//1.StringBuilder bf1 new StringBuilder();StringBuilder bf2 new StringBuilder(10);StringBuilder bf3 new StringBuilder("Hello …

【韩顺平Java笔记】第8章:面向对象编程(中级部分)【272-284】

272. 包基本介绍 272.1 看一个应用场景 272.2 包的三大作用 272.3 包的基本语法 273. 包原理 274. 包快速入门 在不同的包下面创建不同的Dog类 275. 包命名 276. 常用的包 一个包下,包含很多的类,java 中常用的包有: java.lang.* //lang 包是基本包&#xff0c;默认引入&…

5G NR coreset 简介

文章目录 5G 为何引入CORESETCORESET介绍CORESET 分类 5G 为何引入CORESET 在LTE系统中&#xff0c;PDCCH频域占据整个带宽&#xff0c;始于占据每个RB的前1~3个OFDM 符号&#xff0c;这种情况下&#xff0c;UE 只需知道PDCCH 所占据的OFDM 符号数&#xff0c;就可以确定PDCCH…

互联网前后端分离的开发场景,一般会员和数据权限的判断是放在前端还是后端?

推荐学习文档 golang应用级os框架&#xff0c;欢迎stargolang应用级os框架使用案例&#xff0c;欢迎star案例&#xff1a;基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识&#xff0c;这里有免费的golang学习笔…