面试必须要知道的MySQL知识--索引

10 索引

10.1 数据页存储结构

10.1.1 数据页的各个部分

在讲索引之前,让我们看看一个单独的数据页是什么样子的

去除掉一些我们不太需要那么关注的部分后,简化如下:

也就是说平时我们在一个表里插入的一行一行的数据会存储在数据页里,然后数据页里的每一行数据都会按照主键大小进行排序存储,同时每一行数据都有指针指向下一行数据的位置,组成单向链表。

10.1.2 页分裂

随着业务的发生,我们的数据页一般会越来越大,当大到一定程度的时候,就需要再搞一个数据页了,如下图所示

但是这一步骤并不是说简简单单多加一个数据页就 OK,还需要保证新加的数据页中的每一行数据的主键值都要比前面的大才行,所以数据行有可能会在数据页中挪动。具体如下图所示:

10.2 索引页存储结构

10.2.1 概念

上一节我们讲了数据页的存储结构,这一节我们继续学习索引页的存储结构。

我们先思考一个问题,如果我们只有一般的数据页,咱们怎么找到自己想要的数据呢?是不是要将数据页全部遍历,再在每一个页中,通过二分查找查询数据。这么做,实在是太慢了!所以 MySQL 抽象出了一个索引页的概念,它和一般的数据页差不多,只不过存放的是最小主键值和页号。然后后续你查询主键值,就可以在目录里二分查找直接定位到那条数据所属的数据页,接着到数据页里二分查找定位那条数据就可以了,如下图所示

但是随着数据页越来越多,索引页也变得越来越多,这个时候怎么办呢?这个时候 MySQL 会抽象出一个更高层级的索引页,它里面记录的是最小主键值和索引页号。

那么现在问题再次来了,假如你最顶层的那个索引页里存放的下层索引页的页号也太多了,怎么办呢?此时可以再次分裂,再加一层索引,最后不断的向上加,索引页看起来就像下面这个样子了,也就是一颗 B+树。

10.2.1 例子

最后我们以最简单最基础的主键索引来举例,当你为一个表的主键建立起来索引之后,其实这个主键的索引就是一颗 B+树,然后当你要根据主键来查数据的时候,直接就是从 B+树的顶层开始二分查找,一层一层往下定位,最终一直定位到一个数据页里,在数据页内部的目录里二分查找,找到那条数据。

10.3 聚簇索引

10.3.1 特点

我们上面介绍的B+树索引,它有两个特点:

  • 使用记录主键值的大小进行记录和页的排序

  • B+树的叶子节点存储的是完整的用户记录

    符合这两个特点的索引,就是聚簇索引。在 InnoDB 存储引擎中,聚簇索引就是数据的存储方式,InnoDB 存储引擎会自动的为我们创建聚簇索引。

10.4 二级索引

10.4.1 概念

聚簇索引,使用记录主键值的大小进行记录和页的排序,他是和主键强关联的。但是如果查询的条件不是主键,而是其他列呢?这个时候,就要请出咱们的二级索引了。

二级索引也是一颗B+树,但是它的数据页里存放的是主键+目标字段值。换句话说,将聚簇索引中的主键值替换成目标值段,且叶子节点仅存储主键+目标字段值这两个列的值,那么他就是二级索引了。

当你要根据目标字段来查数据的时候,直接就是从 B+树的顶层开始二分查找,一层一层往下定位,最终一直定位到一个数据页里,在数据页内部的目录里二分查找,找到那条数据。但是这条数据只有主键+目标字段值。

10.4.2 图解

10.4.3 回表

如果你的查询结果中还需要有其他值,那么你得再根据主键在聚簇索引这个B+树中,再查找一次,得到最终的结果,这个过程叫做回表。

10.5 联合索引

联合索引也是一颗B+树,但是它的数据页里存放的是主键+多个目标字段值。其他和二级索引类似。

10.6 覆盖索引与回表查询

10.6.1 概念

首先我们要明确一点,覆盖索引,并不是真正的索引,他其实是一种基于索引的查询方式。

不管是二级索引,还是联合索引,如果你的查询结果中没有其他值,只有索引值,那么你得不需要再在聚簇索引这个B+树中,再查找一次,只需要扫描当前索引的叶子节点,就能得到结果,这种就叫做覆盖索引。

10.6.2 例子

select xx1,xx2,xx3 from table order by xx1,xx2,xx3

基于xx1,xx2,xx3建立联合索引

这种情况下,你仅仅需要联合索引里的几个字段的值,那么其实就只要扫描联合索引的索引树就可以了,不需要回表去聚簇索引里找其他字段了。

10.7 如何更好的建立索引

通过前文我们知道了索引其实是一颗一颗的B+树,那么接下来我们介绍一下B+树索引适用的条件。

10.7.1 索引适用的条件

首先我们给出一张示例表,如下:

CREATE TABLE `user` (  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',  `name` varchar(32) NOT NULL COMMENT '用户名',  `age` int(3) NOT NULL COMMENT '年龄',  PRIMARY KEY (`id`),  KEY `index_name_age` (`name`,`age`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='user示例表';

这个例子中,有两个索引,一个是根据id排序的聚簇索引,另一个是跟据name和age排序的二级索引。

注意:二级索引,是先跟据name排序,如果name相同,再根据age排序的。

10.7.1.1 全值匹配

例子:

SELECT * FROM user WHERE name = '第七人格' AND age = '29';

解析:

  • 因为B+树的数据页和记录先是按照name列的值进行排序的,所以先可以很快定位name列的值是“第七人格”的记录位置。

  • 在name列相同的记录里又是按照age列的值进行排序的,所以在name列的值是“第七人格”的记录里又可以快速定位age列的值是’29’的记录。

101.7.1.2 匹配左边的列

【例子】:

SELECT * FROM user WHERE name = '第七人格';

解析:

  • 因为B+树的数据页和记录先是按照name列的值进行排序的,所以先可以很快定位name列的值是“第七人格”的记录位置。

【反例】:

SELECT * FROM user WHERE age = '29';

解析:

  • 因为B+树的数据页和记录先是按照name列的值进行排序的,所以先可以很快定位name列的值是“第七人格”的记录位置,但是现在用age去找,你想想能找到吗?当然找不到了,你都没找到第一层排序的name值,怎么能找到下层的age呢?

10.7.1.3 匹配列前缀

【例子】:

SELECT * FROM user WHERE name like '第七%';

解析:

  • 因为B+树的数据页和记录先是按照name列的值进行排序的,那么的值是按照字符串排序的,字符串本质是按照字符排序的,这个例子中“第七”是被排好序了的,也可以很快定位name列的值是“第七…”的记录位置。

【反例】:

SELECT * FROM user WHERE name like '%第七%';

或者

SELECT * FROM user WHERE name like '%第七';

解析:

  • “第七”并没有排好序,所以无法使用索引。

10.7.1.4 匹配范围值

【例子】:

SELECT * FROM user WHERE name > 'Anna' AND name < 'Ziad';

解析:

  • name能用到索引。

【例子】:

SELECT * FROM user WHERE name > 'Anna' AND age < '35';

解析:

  • name能用到索引,age不能。

【思考】:

SELECT * FROM user WHERE name = 'Anna' AND age < '35';

请读者思考上面可以使用到索引吗?为什么?

10.7.1.5 排序

【例子】:

SELECT * FROM user ORDER BY name,age LIMIT 1;

解析:

  • 这个是可以用到索引的,因为他是按照联合索引的字段顺序去进行order by排序的,这样就可以直接利用联合索引树里的数据有序性,到索引树里直接按照字段值的顺序去获取数据。

【反例】:

SELECT * FROM user ORDER BY name ASC,age DESC;

解析:

  • 既有升序又有降序,没办法使用索引。

10.7.1.6 分组

【例子】:

SELECT name,age FROM user GROUP BY name , age;

解析:

  • 这个是可以用到索引的,原因可以类比排序。

10.7.2 阿里巴巴索引规约

  • 【强制】业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。

  • 【强制】超过三个表禁止 join。需要 join 的字段,数据类型保持绝对一致;多表关联查询时, 保证被关联的字段需要有索引。

  • 【强制】在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据 实际文本区分度决定索引长度。

  • 【强制】页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。

  • 【推荐】如果有 order by 的场景,请注意利用索引的有序性。order by 最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。

  • 【推荐】利用覆盖索引来进行查询操作,避免回表。

  • 【推荐】利用延迟关联或者子查询优化超多分页场景。

  • 【推荐】建组合索引的时候,区分度最高的在最左边。

以上规约摘自阿里巴巴开发手册,通过前面的学习,我相信大家可以从更深层次理解这些规约了,而不是一味的死记硬背。

10.8 执行计划与性能优化浅谈

10.8.1 总览

在生产中我们判断一个SQL写的好不好,一般都是通过EXPLAIN关键字,看他的执行计划的。

首先我们看看执行计划长什么样子,我们执行以下SQL

EXPLAIN SELECT * FROM user WHERE name = '第七人格' AND age = '29';

得到的执行计划如下:

10.8.2 要素

10.8.2.1 id

这个字段对性能优化来说,不太重要,我们只需要知道,在一个大的查询语句中每个SELECT关键字都对应一个唯一的id 就行了。

10.8.2.2 select_type

SELECT关键字对应的那个查询的类型,也不重要。

10.8.2.3 table

表名,意思就是查的哪个表,也不是很重要。

10.8.2.4 partitions

匹配的分区信息,我们接触不到这个知识点,99.9%都是null。

10.8.2.5 type

针对单表的访问方法,这个就非常重要了。

完整的类型如下:system,const,eq_ref,ref,fulltext,ref_or_null,index_merge,unique_subquery,index_subquery,range,index,ALL 。

这里我们针对比较常见和重要的几种类型介绍一下。

const,常量级,一般出现这个,就表示,你写的SQL非常好,性能非常快。哪些属于const呢?比如select * from user where id=x,或者select * from user where name=x这样的的语句,直接就可以通过聚簇索引或者二级索引+聚簇索引回表,轻松查到你要的数据。

值的一提的是,这里的二级索引必须是唯一索引。如果是普通索引,那么就是ref了,就如我们总览中的执行计划一样。当然,ref也是一种非常快的查询方式。

range也是一种常见的查询方式,一般出现在范围查询中,比如我们前面举的一个例子select * from user where name>=x and name <=x,假设name就是一个普通索引,此时就必然利用索引来进行范围筛选,一旦利用索引做了范围筛选,那么这种方式就是range。

我们再回忆一下这个sql,select name,age from user where age = ‘29’,因为age不是索引最左边的值,所以它是没法从联合索引的根节点二分查找快速跳转的,但是因为他的结果和条件都在索引里,所以MySQL的优化器,会直接扫描这个联合索引,一个个的遍历。也就是说,针对这种只要遍历二级索引就可以拿到你想要的数据,而不需要回源到聚簇索引的访问方式,就叫做index访问方式,这种访问方式相对于前面几种,就要慢的多。

最后再看看ALL,顾名思义,全表扫描,一般属于我们要杜绝的情况。

10.8.2.6 possible_keys

可能用到的索引。

10.8.2.7 key

实际上使用的索引。

10.8.2.8 key_len

实际使用到的索引长度。

10.8.2.9 ref

当使用索引列等值查询时,与索引列进行等值匹配的对象信息。

10.8.2.10 rows

预估的需要读取的记录条数,这个值按道理来说,越小越好。

10.8.2.11 filtered

某个表经过搜索条件过滤后剩余记录条数的百分比,对于单表查询来说,这个值没什么意义,都是100%,但是对于多表查询就有意义了,越小越好。

10.8.2.12 Extra

一些额外的信息。比如Using where,Using index,Using filesort等等。我们用group by、union、distinct之类的语法的时候,要是没法直接利用索引来进行分组聚合,那么MySQL会直接基于临时表来完成,会有大量的磁盘操作,也就是会使用文件排序(Using filesort)。这种情况一般也是需要避免的。

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

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

相关文章

Leetcode算法系列| 3. 无重复字符的最长子串

目录 1.题目2.题解C# 解法一&#xff1a;滑动窗口算法C# 解法二&#xff1a;索引寻找Java 解法一&#xff1a;滑动窗口算法Java 解法二&#xff1a;遍历字符串 1.题目 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例1: 输入: s "ab…

数据结构——链式二叉树的实现(详解)

呀哈喽。我是结衣。 不知道大家的递归学到怎么样呢&#xff1f;如果大家的递归功底不是很好&#xff0c;那么我相信在学完这篇文章后大家一定会对递归有一个更深层次的了解的。 构造链式二叉树 在学习二叉树的基本操作前&#xff0c;需先要创建一棵二叉树&#xff0c;然后才能…

直播场景视频和特效解决方案

直播已经成为企业与消费者互动的重要方式&#xff0c;如何提供优质的直播内容&#xff0c;提升直播效果&#xff0c;以及实现直播内容的商业化转化&#xff0c;一直是企业面临的重要挑战。为此&#xff0c;美摄科技提供了一套全面的直播场景解决方案&#xff0c;帮助企业解决这…

爬虫学习 异步爬虫(五)

多线程 多进程 协程 进程 运行中的程序 线程 被CPU调度的执行过程,操作系统 运算调度的min单位 在进程之中,进程中实际运作单位 from threading import Thread#创建任务 def func(name):for i in range(100):print(name,i)if __name__ __main__:#创建线程t1 Thread(target …

0 NLP: 数据获取与EDA

0数据准备与分析 二分类任务&#xff0c;正负样本共计6W&#xff1b; 数据集下载 https://github.com/SophonPlus/ChineseNlpCorpus/raw/master/datasets/online_shopping_10_cats/online_shopping_10_cats.zip 样本的分布 正负样本中评论字段的长度 &#xff0c;超过500的都…

uniapp 导航分类

商品分类数据&#xff0c;包括分类名称和对应的商品列表点击弹出 列表的内容 展示效果如下&#xff1a; 代码展示 ①div部分 <view class"container"><view class"menu-bar"><view class"menu"><view class"menu-sc…

【hive-design】hive架构详解:描述了hive架构,hive主要组件的作用、hsql在hive执行过程中的底层细节、hive各组件作用

文章目录 一. Hive Architecture二. Metastore1. Metastore Architecture2. Metastore Interface 三. Compiler四. hive架构小结 本文主要讨论了 描述了hive架构&#xff0c;hive主要组件的作用详细描述了hsql在hive执行过程中的底层细节描述了hive各组件作用 一. Hive Archite…

Kubernetes入门篇

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容Kubernetes是什么&#xff1f;为什么需要 Kubernetes&#xff0c;它能做什么&#xff1f;Kubernetes 版本进化Kubernetes 概念Kubernetes 中 3 个重要概念 &#x1f4e2;文章总结&#x1f4e5;博主目标 &#x1f50a;博主介…

毫米波雷达DOA角度计算----Capon算法

算法实现如下&#xff1a; parameter&#xff1a;雷达参数设置。 antVet&#xff1a;目标点 对应的非相参积累天线数据。 function [angle,doa_abs] caponMethod(parameter,antVec)txAntenna parameter.txAntenna; % 发射天线 [1 1]rxAntenna parameter.rxAntenna; % 接…

Java第十二篇:连接安全版kafka(Kerberos认证)出现的问题解答

Could not find a ‘KafkaClient’ entry in the JAAS configuration 问题现象 问题原因 原因没有找到&#xff0c;怎么引起的倒是很清楚。原因就是找到不到指定路径下的kafka_client_jaas.conf文件&#xff0c;别看我的路径带了两个//&#xff0c;但没问题的&#xff0c;等同…

梦极光(ez_re?)

ez_re 先查壳看看&#xff0c;没有壳 32位 我先说说这道题 打开分析找到主函数 在这里就是flag了&#xff0c;用十六进制转ascii码 我们先运行这个程序看看 我想说说我的想法 首先没看出来这里是十六进制转ascii码其次41D538数组用来干啥来的&#xff1f;题目里面给出的请…

Micropython STM32F4外部中断实验

Micropython STM32F4外部中断实验 &#x1f4cc;固件刷可参考前面一篇《STM32刷Micropython固件参考指南》&#x1f33f; 相关篇《Micropython STM32F4入门点灯》&#x1f4cd;固件下载&#xff1a;https://micropython.org/download/?mcustm32f4&#x1f516;本例程基于STM32…

网络运维与网络安全 学习笔记2023.11.28

网络运维与网络安全 学习笔记 第二十九天 今日目标 OSPF汇总之域间路由、OSPF汇总之外部路由、OSPF链路认证 OSPF安全认证之区域认证、OSPF虚链路 OSPF汇总指域间路由 项目背景 企业内网运行多区域的OSPF网络&#xff0c;在R1 上存在多个不稳定的链路 R1上的不稳定链路&a…

纯cpp如何模拟qt的信号与槽

纯cpp如何模拟qt的信号与槽 我之前是如何使用bind的?一.demo示例二.简单来讲,c自带的bind与function函数,如何实现类似信号与槽的机制1. 简单语法2. function与bind联动尝试1尝试2真正实现流程图 自我反思 我之前是如何使用bind的? 一.demo示例 using MsgHander std::funct…

数据结构-交换排序(冒泡、快速)

冒泡排序 基本思想 先将第一个记录与第二个记录比较&#xff0c;将较大的记录放到第二个位置上&#xff0c;之后再将第二个记录与第三 个记录比较&#xff0c;将较大的记录放到第三个位置上&#xff0c;如此类推&#xff0c;知道比较完最后一个位置&#xff0c;此时注意到 …

红队攻防之hash登录RDP

没什么好害怕&#xff0c;孩子放心去飞吧&#xff0c;在你的身后有个等你的家 Restricted Admin Mode 受限管理模式是一项 Windows 功能&#xff0c;可防止将 RDP 用户的凭据存储在建立 RDP 连接的计算机的内存中。 这是用来防止用户&#xff08;管理员&#xff09;在 RDP 进…

shopee数据:如何获取Shopee平台的数据

在如今快速发展的跨境电商市场中&#xff0c;Shopee&#xff08;虾皮&#xff09;作为一个备受关注的平台&#xff0c;主要服务于东南亚市场。对于卖家来说&#xff0c;了解Shopee平台的数据是非常重要的&#xff0c;因为这可以帮助他们更好地了解市场趋势、优化商品策略并提高…

Ubuntu 20.0 + mysql 8.0 用户和密码修改

第一步 下载&#xff08;简单,注意联网&#xff09;Ubuntu 终端输入以下两行命令 (1) 数据库的服务端及客户端数据库的开发软件包 sudo apt-get install mysql-server mysql-client (2) 数据库的开发软件包 sudo apt-get install libmysqlclient-dev 第二步 查看是否安装成功 …

血的教训--redis被入侵之漏洞利用复现--总览

血的教训–redis被入侵之漏洞利用复现–总览 相信大家对于自己的服务器被入侵&#xff0c;还是比较憎恨的&#xff0c;我的就被攻击了一次&#xff0c;总结经验&#xff0c;自己也是整理了这一个系列&#xff0c;从最基础到最后面的自己总结被攻破的步骤&#xff0c;非常清晰的…

20世纪30年代的大危机

背景 1929年9月&#xff0c;美国财政部部长安德鲁梅隆向公众保证“现在没有担心的理由&#xff0c;这一繁荣的高潮将会继续下去”。 当时流行的一首儿歌&#xff1a;“梅隆拉响汽笛&#xff0c;胡佛敲起钟&#xff0c;华尔街发出信号&#xff0c;美国往地狱里冲&#xff01;”…