2022/12/17 mysql 索引基本原理解读

news2024/9/25 3:27:03

1什么是索引

索引是帮助MySQL 高效获取数据的数据结构,通过使用索引可以在查询的过程中,使用优化隐藏器,提高系统的性能。
https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
在这里插入图片描述
优势

  1. 类似于书籍的目录索引,提高数据检索的效率,降低数据库的IO成本。
  2. 通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。
    劣势
    1)实际上索引也是一张表,该表中保存了主键与索引字段,并指向实体类的记录,所以索引列也是要占用空间的。
    2)虽然索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行INSERT、UPDATE、DELETE,因为更新表时,MySQL 不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。

2索引的分类

类别特点
普通索引由关键字KEY或INDEX定义的索引 加快对数据的访问速度 普通索引允许被索引的数据列包含重复的值
唯一索引某个数据列将只包含彼此各不相同的值 UNIQUE 唯一索引可以保证数据记录的唯一性,可以允许空值但是只能有一个
主键索引一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录,使用关键字PRIMARY KEY 来创建,不可以为空值
联合索引索引可以覆盖多个数据列,如像INDEX(columnA, columnB)索引

3索引的基本操作

3.1建表时就设计好索引

CREATE TABLE `tb_user_info` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `user_name` varchar(255) NOT NULL DEFAULT '',
  `user_age` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `index_name_age` (`user_name`,`user_age`),
  KEY `index_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4;

3.2ALTER 命令添加和删除索引

ALTER TABLE tb_user_info ADD INDEX index_id_name_age(user_id, user_name, user_age);

在这里插入图片描述

ALTER TABLE tb_user_info DROP INDEX index_id_name_age;

在这里插入图片描述

4 复合索引-最左前缀原理

where子句中使用最频繁的一列放在最左边;我们在(a,b,c)字段上建了一个联合索引,所以这个索引是先按a 再按b 再按c进行排列的,所以:以下的查询方式都可以用到索引

select * from table where a=1;
select * from table where a=1 and b=2;
select * from table where a=1 and b=2 and c=3

上面三个查询按照 **(a ), (a,b ),(a,b,c )**的顺序都可以利用到索引,这就是最左前缀匹配。

如果查询语句是:
select * from table where a=1 and c=3; 那么只会用到索引a。
如果查询语句是:
select * from table where b=2 and c=3; 因为没有用到最左前缀a,所以这个查询是没有用到索引的。

5索引的底层原理 B+树

CREATE TABLE `t_emp` (
  `id` int NOT NULL,
  `name` varchar(20) DEFAULT NULL,
  `age` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `test-center`.`t_emp` (`id`, `name`, `age`) VALUES (1, 'a', 23);
INSERT INTO `test-center`.`t_emp` (`id`, `name`, `age`) VALUES (8, 'f', 53);
INSERT INTO `test-center`.`t_emp` (`id`, `name`, `age`) VALUES (2, 'b', 26);
INSERT INTO `test-center`.`t_emp` (`id`, `name`, `age`) VALUES (9, 'v', 13);
INSERT INTO `test-center`.`t_emp` (`id`, `name`, `age`) VALUES (3, 'c', 27);
INSERT INTO `test-center`.`t_emp` (`id`, `name`, `age`) VALUES (4, 'a', 32);
INSERT INTO `test-center`.`t_emp` (`id`, `name`, `age`) VALUES (5, 'd', 22);
INSERT INTO `test-center`.`t_emp` (`id`, `name`, `age`) VALUES (6, 'd', 22);
INSERT INTO `test-center`.`t_emp` (`id`, `name`, `age`) VALUES (7, 'e', 21);

在这里插入图片描述
查询出来的时候,id-是有序的。
在这里插入图片描述
这是为什么呢?主键索引进行了排序。
在这里插入图片描述
B+树结构:
在这里插入图片描述
B树结构:
在这里插入图片描述
B+Tree是在B-Tree(B树)基础上的一种优化,使其更活合实现外存储索结构,lnnoDB存储引警就是用B+Tree实现其索引结构,B-Tree结构图中可以看到每个节点中不仅包含数据的key值,还有data值,而每一个页的存储空间是有限的,如果data数据较大时将会导致每个节点(即一个页)能存储的key的数量很小,当存的数据量很大时同样会导致B-Tree的深度较大,增大查询时的磁盘I/0次数,进而影响查询效率;
在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+Tree的高度。

顶层目录页是常驻内存的,是不用I/O的。

6索引结构

索引是在MYSQL的存储引擎层中实现的,而不是在服务层实现的。所以每种存储擎的索引都不一定完全相同,也不是所有的存储引擎整都支持所有的索引类型的。MySQL目前提供了以下2种索引:
BTREE 索 :最常见的索引类型,大部分索引都支持 B 树索引。
HASH 索引: 只有Memory引擎支持 ,使用场景简单。
在这里插入图片描述
我们平常所说的索引,如果没有特别指明,都是指B+树。其中聚簇索引、复合索引、前缀索引、唯一索引默认都是使用 B+tree 索引,统称为 索引。

7聚簇索引 & 非聚簇索引

mysql的索引类型跟存储引擎是相关的,innodb存储引擎数据文件跟索引文件全部放在ibd文件中, 而myisam的数据文件放在myd文件中,索引放在myi文件中,其实区分聚簇索引和非聚簇索引非常简单:只要判断数据跟索引是否存储在一起就可以了
聚簇索引:数据 && 索引存储在一 起,没有存储在一起的叫做非聚簇索引。
innodb存储引擎在进行数据插入的时候,数据必须要跟某一个索引列存储在一 起,这个索引列可以是主键,如果没有主键,选择唯一键,如果没有唯一键,选择6字节的row_id来进行存储,数据必定是跟某一个索引绑定在一起的,绑定数据的索引叫做聚簇索引,非聚簇索引的叶子节点中存储的数据不再是整行的记录,而是聚簇索引的索引值,innodb中既有聚簇索引也有非聚簇索引。

如果查询条件为非聚簇索引,需要扫描两次B+树:第一次扫描通过普通索引定位到聚簇索引的值,然后第二次扫描通过聚簇索引的值定位到要查找的行记录数据。
在这里插入图片描述
innoDB使用的是聚族索引,将主键组织到一棵B+树中,而行数据就储存在叶子节点上,若使用"where d =14"这样的条件查找主键,则按照B+树的检索算法即可查找到对应的叶节点,之后获得行数据。

若对Name列进行条件搜索,则需要两个步骤:第一步在辅助索引B+树中检索Name,到达其叶子节点获取对应的主键,第二步使用主键在聚簇索引B+树中再执行一次B+树检索操作,最终到达叶子节点即可获取整行数据。

这就引出了回表查询:
先通过普通索引的值定位聚簇索引值,再通过聚簇索引的值定位行记录数据,需要扫描两次索引B+树,它的性能较扫一遍索引树更低。我们应该避免这种情况,所以使用索引覆盖来解决这个问题。

8回表查询

常见的方法是:将被查询的字段,建立到联合索引里去。

 create table user(
		id int(10) auto_increment,
		name varchar(30),
		age tinyint(4),
		primary key (id),
		index idx_age (age)
)engine=innodb;

insert into user(name,age) values('张三',30);
insert into user(name,age) values('李四',20);
insert into user(name,age) values('王五',40);
insert into user(name,age) values('刘八',10);

1、实现:

select id,age from user where age = 10;

explain分析:因为age是普通索引,使用到了age索引,通过一次扫描B+树即可查询到相应的结果,这样就实现了覆盖索引
在这里插入图片描述
2、实现:

select id,age,name from user where age = 10;

explain分析:age是普通索引,但name列不在索引树上,所以通过age索引在查询到id和age的值后,需要进行回表再查询name的值。此时的Extra列的NULL表示进行了回表查询。
在这里插入图片描述
为了实现索引覆盖,需要建组合索引idx_age_name(age,name):

drop index idx_age on user;
create index idx_age_name on user(`age`,`name`);

explain分析:此时字段age和name是组合索引idx_age_name,查询的字段id、age、name的值刚刚都在索引树上,只需扫描一次组合索引B+树即可,这就是实现了索引覆盖,此时的Extra字段为Using index表示使用了索引覆盖。
在这里插入图片描述

9使用聚簇索引的优势

MYISAM使用的是非聚簇索引,非聚簇索引的两个B+树看上去没什么不同,节点的结构完全一致只是存储的内容不同而已,主键索引B+树的节点存储了主键,辅助索引B+树存储了辅助键,表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。
在这里插入图片描述
问题: 每次使用辅助索引检索都要经过两次B+树查找,看上去聚索引的效率明显要低于非非聚簇索引,这不是多此一举吗? 聚族索引的优势在哪?

1.由于行数据和聚簇索引的叶子节点存储在一起,同一页中会有多条行数据,访问同一数据页不同行记录时,已经把页加载到了Buffer中缓存器),再次访问时,会在内存中完成访问,不必访问磁盘。这样主键和行数据是一起被载入内存的,找到叶子节点就可以立刻将行数据返回了,如果按照主键Id来组织数据,获得数据更快。

2.辅助索引的叶子节点,存储主键值,而不是数据的存放地址。好处是当行数据放生变化时,索引树的节点也需要分裂变化,或者是我们需要查找的数据,在上一次I/O读写的存中没有,需要发生一次新的IO操作时,可以避免对辅助索引的维护工作,只需要维护聚簇索引树就好了。另一个好处是,因附注索引存放的是主键值,减少了辅助索引占用的存储空间大小。

10主键最好不要使用uuid

当使用主键为聚簇索引时,主键最好不要使用uuid,因为uuid的值太过离散,不适合排序且可能出现新增加记录的uuid,会插入在索树中间的位置,导致索引树调整复杂度变大,消耗更多的时间和资源。

建议使用int类型的自增,方便排序并且默认会在索引树的未尾增加主键值,对索引树的结构影响最小。而且,主键值占用的存储空间越大,辅助索引中保存的主键值也会跟着变大,占用存储空间,也会影响到I/O操作读取到的数据量。

11为什么主键通常建议使用自增id

聚簇索引的教据的物理存放顺序与索引顺序是一致的,只要索引是相邻的,那么对应的据一定也是相邻的存放在磁盘上的。如果主键不是自增id,那么它会不断地调整数据的物理地址、分页,当然也有其他一些措施来减少这些操作,但却无法彻底避免。如果是自增的,那就简单了,它只需要一页一页地写,索引结构相对紧凑,磁盘碎片少,效率也高。

12索引无法使用到的情况

1、like 以%开头,索引无效;当like前缀没有%,后缀有%时,索引有效。
2、当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效。
3、对于联合索引而言,违反最左匹配原则。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/97921.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java缓存模块,ehcache/guava cache/自定义spring的CacheManager/自定义缓存

如ehcache,guava cache,redis 也有将ehcache,guava cache分级为单机缓存 将redis分为分布式缓存 ehcache官网:https://www.ehcache.org/ 这里主要说下ehcache和guava cache 单独使用ehcache(当然真正企业开发并不会单独使用ehcache,而是会和Spring或者SpringBoot集成使用) …

什么是建筑中的“光储直柔”

建筑“光储直柔”与零碳电力如影随形(2021) 《2030 年前碳达峰行动方案》(国发〔2021〕23 号)中明确提出:提高建筑终端电气化水平,建设集光伏发电、储能、直流配电、柔性用电于一体的“光储直柔”建筑。到 …

广告、推荐模型加速策略整理

当我们尝试那些开箱即用的GPU服务时,很快意识到在经济高效地利用GPU运行推荐模型服务之前需要对其优化。我们首先使用分析工具来分析在模型推理过程中发生了什么,在仔细观察分析结果时,我们注意到时间线上有大量的小CUDA Kernel在执行。 这是…

[附源码]Python计算机毕业设计Django汽配管理系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,我…

linux内核内存管理-brk系统调用

【推荐阅读】 深入linux内核架构--进程&线程 浅谈linux 内核网络 sk_buff 之克隆与复制 浅析linux内核网络协议栈--linux bridge 尽管可见度不高,brk也许是最常使用的系统调用了,用户进程通过它向内核申请空间。人们常常并不意识到在调用brk&…

Python Flask构建微信小程序订餐系统 (三)

🔥 管理员登录和列表界面 🔥 账号相关登录界面 1、新建 User 对象文件 2、新建login (登录的方法)、edit (编辑的方法)、reset-pwd(重置密码的方法)方法 3、新建对应的视图层 账户管理相关界面 1、新建 Account 对象文件 2、新建index(账户列表)、set(新…

基于 Spring Cloud 的微服务脚手架

基于 Spring Cloud 的微服务脚手架 作者: Grey 原文地址: 博客园:基于 Spring Cloud 的微服务脚手架 CSDN:基于 Spring Cloud 的微服务脚手架 本文主要介绍了基于 Spring Cloud Finchley 和 Spring Boot 2.0.x 版本的微服务脚…

2006-2019年280个地级市绿色全要素生产率含原始数据和测算结果

2006-2019年280个地级市绿色全要素生产率含原始数据和测算结果 1、时间:2006-2019年 2、来源:原始数据来自各省NJ 城市NJ、各市NJ、各市社会统计GB 3、范围:包括280个地级市 4、指标包括: 投入:地级市市辖区从业人…

Spring Boot热部署配置

⭐️前言⭐️ 在我们进行Spring Boot项目的编写过程中,会有局部的代码,发生一些变动,这时候,我们只有将项目重启,发生变动的代码才能够生效,为了解决这个问题,我们可以设置Spring Boot热部署&a…

ClassLoader 隔离性的基石是namespace,证明给你看

一、背景 朋友:在我知识体系中ClassLoader的双亲委派机制是流畅丝滑的,可是看到通过委派执行类加载来保障这种分治能力,进而达到了类资源的隔离性突然就感觉有点陌生和排斥呢? 我:类的命名空间有了解嘛? …

Tableau可视化设计案例-01Tableau简介,条形图与直方图

文章目录Tableau可视化设计案例Tableau简介,条形图与直方图Tableau界面介绍Tableau绘制条形图2.1条形图1 各地区酒店数量2.2条形图2:各地区酒店均价2.3堆积图:价格等级堆积图Tableau绘制直方图3.1直方图概念与用途3.2创建评分直方图Tableau饼…

python中的split函数

返回数据类型为list # split以空格切片,返回数据类型为list a"I LOVE Python" print(a.split(" ")) print(type(a.split(" ")))运行结果如下: 可指定分隔符 # split以.切片,返回数据类型为list b"www.baidu.com" print…

Python工程师培训要多久?

Python作为目前备受初学者青睐的编程语言,学习的难度与其他语言相比,还是比较容易入门的。当然,一些零基础的初学者想要一两个月就能速成Python,还是不太可能的。尤其是想在学完之后应聘相关岗位,就算是最快的学习方式…

Dubbo 4 Dubbo 高级特性 4.2 Dubbo 常用高级配置 4.2.4 重试 4.2.5 多版本

Dubbo 【黑马程序员Dubbo快速入门,Java分布式框架dubbo教程】 4 Dubbo 高级特性 文章目录Dubbo4 Dubbo 高级特性4.2 Dubbo 常用高级配置4.2.4 重试4.2.5 多版本4.2 Dubbo 常用高级配置 4.2.4 重试 之前我们已经完成 了超时的配置 而且知道 了如果服务提供方 和消…

Linux 中存在太多的垃圾文件?

不知道大家是否也跟我一样,是一只要把的自己电脑文件安排的条理有序,把没用的文件会及时删掉的程序猿呢?如果是的话,那么我们可以愉快地探讨下文章的内容。如果不是的话,你也可以留下来凑凑热闹嘛(>- 下面要介绍的是…

基于java+springmvc+mybatis+vue+mysql的邮票鉴赏系统及实现

项目介绍 随着邮票行业的发展,邮票市场已经有了越来越多的爱好者加入。收藏邮票,也就成了邮票收藏爱好者一个有爱又恨的话题。没错,大量的邮票收藏确实是对知识面的增广和一种成就感的满足。但是面对越来越多的邮票。五花八门各种各样的邮票…

十四、CANdelaStudio入门-DID池

本专栏将由浅入深的展开诊断实际开发与测试的数据库编辑,包含大量实际开发过程中的步骤、使用技巧与少量对Autosar标准的解读。希望能对大家有所帮助,与大家共同成长,早日成为一名车载诊断、通信全栈工程师。 本文介绍CANdelaStudio的DID池,欢迎各位朋友订阅、评论,可以提…

【C++进阶】C++11新特性上篇(万字详解)

🎇C学习历程:入门 博客主页:一起去看日落吗持续分享博主的C学习历程博主的能力有限,出现错误希望大家不吝赐教分享给大家一句我很喜欢的话: 也许你现在做的事情,暂时看不到成果,但不要忘记&…

Dubbo 4 Dubbo 高级特性 4.2 Dubbo 常用高级配置 4.2.6 负载均衡

Dubbo 【黑马程序员Dubbo快速入门,Java分布式框架dubbo教程】 4 Dubbo 高级特性 文章目录Dubbo4 Dubbo 高级特性4.2 Dubbo 常用高级配置4.2.6 负载均衡4.2 Dubbo 常用高级配置 4.2.6 负载均衡 【举个栗子】 现在 同一个服务 提供者,我们把它 部署在了…

Dijkstra迪杰斯特拉算法

1.场景 用于计算一个节点到其他节点的最短路径,特点是由其实点位中心向外层扩展(BFS思想),直至扩展到终点为止 2.认识 https://blog.csdn.net/weixin_57128596/article/details/126982769?ops_request_misc%257B%2522request%…