MySQL优化的底层逻辑

文章目录

  • 前言
  • 索引的底层结构
  • 数据与索引的关系
    • 聚簇索引的数据存储
    • 普通索引的数据存储
  • 索引的命中逻辑
  • 怎么理解索引失效
  • 总结

前言

去年刚开始写博客的时候写了一篇《MySQL性能调优参考》,文章中提到优化的几个技巧,比如数据类型的使用、范式和反范式的合理使用、索引的使用及其使用的注意事项等等。其中我们接触最多的就是索引,你可能知道索引的底层结构是B+Tree、使用索引要遵守最左匹配原则,那你知道为什么要用B+Tree、为什么使用索引有那么多注意事项吗?所以还是要知其然知其所以然,看完这篇文章你就懂了。

索引的底层结构

首先,MySQL索引的存储不仅仅只有B+Tree的结构,还有Hash和全文,这个在创建索引时可以指定。

MySQL中常用的InnoDB存储引擎默认使用B+Tree结构,毕竟使用MySQL时范围查找的场景是最多的,当然如果等值查询比如热点数据这种场景可以使用Hash索引,如果有大量的文本数据需要搜索和处理,使用全文索引是一个常见的选择。这里只对B+Tree索引展开介绍,如果不了解B+Tree的可以先了解下前置知识《常见的数据结构及应用》。

数据与索引的关系

要想知道在使用索引为什么要有那么多的注意事项和原则,我们需要先了解一下数据和索引的关系。接下来我通过一个简单例子,说明一下B+Tree索引在存储数据中的具体实现。

先创建一张商品表,设置id为主键:

CREATE TABLE `goods`  (
  `id` int PRIMARY KEY NOT NULL,
  `goods_no` varchar(20)  DEFAULT NULL,
  `goods_name` varchar(255) DEFAULT NULL,
  `goods_price` decimal(10, 2) DEFAULT NULL
)

表中的数据如下:
在这里插入图片描述

聚簇索引的数据存储

在向MySQL插入一行数据时,默认情况下,会根据主键字段的数据作为索引键值构建B+Tree索引,这个过程会遵循B+Tree的规则。goods表中的这些数据在B+Tree中的逻辑结构如下图

在这里插入图片描述

可以看到在非叶子节点上只存放了主键列的值,而叶子节点存放了主键对应的整行数据,这种索引又叫「聚簇索引」 也叫「主键索引」 。当sql句为 select id from goods 或者 select * from goods where id = 1 时都会通过这个索引进行查询到数据,这个可以通过执行计划看到

在这里插入图片描述

普通索引的数据存储

而我们自行设置的其他索引都称之为「普通索引」或「二级索引」或者是「非聚簇索引」,在向MySQL插入一行数据时除了会根据主键构建一个聚簇索引,还会根据其他索引列构建对应的普通索引。这里为goods_no、goods_name列创建一个普通索引后,表中的数据在这个索引中逻辑结构如下图

在这里插入图片描述

可以看到在普通索引中每个非叶子节点的键值存放的是索引列的数据,而叶子节点不仅存放了索引列的数据,还存放了对应的主键值。

索引的命中逻辑

那么,问:那么请问,当执行以下sql时会使用哪个索引?为什么?

sql1:select id,goods_name from goods where goods_no='00001'
sql2:select id,goods_name,goods_price from goods where goods_no='00001'
sql3:select id,goods_name,goods_price from goods where goods_name='goods1'

sql1中使用了goods_no、goods_name创建的普通索引。因为查询的字段idgoods_name都在这个索引的叶子节点中,可以直接返回这些数据,所以不用再去其他地方查询,这个过程也叫做「覆盖索引」,执行计划中的Using index 就可以说明。

在这里插入图片描述

sql2中使用了普通索引和主键索引。因为要查询的goods_price在普通索引没有找到,所以在拿到主键后会去主键索引中再查找一次,这个过程叫做「回表」,也就是说要查两个 B+Tree 才能查到数据(如下图)。通常情况下要尽量避免回表操作,因为多一次扫描查询效率就会下降一些。

在这里插入图片描述

sql3没有使用索引,走的是全表扫描。首先条件字段并未使用到普通索引,因为不符合「最左匹配原则」。其次查询字段id,goods_name,goods_price在两个索引中都无法匹配,因此走了全表扫描,这种现象也叫「索引失效」。

怎么理解索引失效

不论是WHERE条件也好,查询字段也罢,是否使用索引或者使用哪个索引都是「优化器」来决定的,以下几个是优化器工作时索引失效的例子及说明:

  1. 当索引列的唯一值与总行数的区分度很小,比如索引列的值就是男和女,那么优化器就会忽略索引直接全表扫描,因为这种情况下即使通过索引定位数据,也会因为索引列的重复去访问大部分的数据页,加上维护索引以及访问索引的开销,这样下来还不如直接去访问数据页。
  2. 当优化器看到WHERE条件中有OR关键字时,会看前后两个字段是否都是索引列,因为OR的含义就是两个只要满足一个即可,所以只要有一个不是索引列就会进行全表扫描。
  3. 说一下sql3的「最左匹配原则」,当构建联合索引(goods_no,goods_name)时,会先对goods_no进行排序插入,如果遇到goods_no相同时再对goods_name进行排序插入,所以优化器在看到查询字段goods_name与索引字段顺序不一样时就会忽视掉这个索引,从而导致索引失效。如果符合最左匹配原则,在根据索引查找数据时会先根据goods_no进行比较,在goods_no相同时再根据goods_name进行比较。
  4. 还有大家都知道的索引列使用函数、表达式会失效,为什么?因为B+Tree中的节点存放的是列的原始数据,你拿一个经过函数或者表达式计算的值来查找当然不认识了。
    5 还有等等索引失效场景。

总结

所以我们不需要背索引失效场景以及索引使用的注意事项,只要知道数据在B+Tree索引中是怎样存储的、优化器是怎么选择索引的,这些那些的原则、注意事项还需要背吗?还是那句话,知其然知其所以然。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CI/CD --git版本控制系统

目录 一、git简介 二、git使用 三、github远程代码仓库 一、git简介 Git特点: 速度简单的设计对非线性开发模式的强力支持(允许成千上万个并行开发的分支)完全分布式有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数…

【C++学习手札】模拟实现vector

🎬慕斯主页:修仙—别有洞天 ♈️今日夜电波:くちなしの言葉—みゆな 0:37━━━━━━️💟──────── 5:28 🔄 ◀️ ⏸ ▶️ ☰…

微信小程序Error: ENOENT: no such file

问题描述 当编译的时候 会提示找不到这个文件(index),但是确信项目目录里已经删除了该页面路径,并且app.json的pages列表中也 导致这个问题应该是:新添加了文件,后面删除了或者修改了文件名,导…

MySQL初始化报错。VCRUNTIME140_1.dll缺失

从自己电脑内搜索此dll,粘贴到服务器的以下位置即可。

电路综合-基于简化实频的集总参数电路匹配3-将任意阻抗用集总参数匹配至归一化阻抗

电路综合-基于简化实频的集总参数电路匹配3-将任意阻抗用集总参数匹配至归一化阻抗 前面的相关理论: 电路综合-基于简化实频的集总参数电路匹配1 电路综合-基于简化实频的集总参数电路匹配2-得出解析解并综合 理论这两个已经介绍过了,直接给出案例 代码…

「Verilog学习笔记」实现3-8译码器①

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点,刷题网站用的是牛客网 分析 ① 本题要求根据38译码器的功能表实现该电路,同时要求采用基础逻辑门实现,那么就需要将功能表转换为逻辑表达式。 timescale 1ns/1nsmodule d…

Python---练习:编写一段Python代码,生成一个随机的4位验证码

案例:编写一段Python代码,生成一个随机的4位验证码 提前:定义一个字符串 str1 "23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ" 编写Python代码: ① 思考:如果只生成4个字符的验证码&…

黑五来袭,如何利用海外代理进行助力

黑五作为下半年年度尤为重要的一个节日,是各大商家的必争之地,那么海外代理是如何帮助跨境商家做好店铺管理和营销呢? 为什么跨境人都关注海外代理,下面我们来进行介绍。 一、什么是海外代理 海外代理就是我们所说的&#xff1…

锂离子电池充电的系统抖动问题解决方案

前言 在设计锂离子电池充电器时,会因为充电电流波动导致电压波动,系统异常。 所以分析了锂离子电池的特性,给出了几种解决方法。 有纰漏请指出,转载请说明。 学习交流请发邮件 1280253714qq.com 理论 锂电池简单地可看做一…

VBA_MF系列技术资料1-222

MF系列VBA技术资料 为了让广大学员在VBA编程中有切实可行的思路及有效的提高自己的编程技巧,我参考大量的资料,并结合自己的经验总结了这份MF系列VBA技术综合资料,而且开放源码(MF04除外),其中MF01-04属于定…

【算法每日一练]-图论(保姆级教程 篇4(遍历))#传送门 #负环判断 #灾后重建

今天继续 目录 题目:传送门 思路: 题目:负环判断 思路: 题目:灾后重建 思路: 题目:传送 门 思路: 先跑一边floyd,然后依次加入每个传送门,O(n^5)不行…

本地jar导入maven

一、通过dependency引入 1.1. jar包放置&#xff0c;建造lib目录 1.2. pom.xml文件 <dependency><groupId>zip4j</groupId><artifactId>zip4j</artifactId><version>1.3.2</version><!--system&#xff0c;类似provided&#x…

ImportError: DLL load failed while importing _iterative: %1 不是有效的 Win32 应用程序。

问题&#xff1a;这个错误是由于导入的模块 _iterative 找不到有效的 Win32 应用程序导致的。可能是由于你的环境中缺少了某个依赖库或者是版本不匹配的问题。 解决方法&#xff1a; 可以尝试以下几种&#xff1a; 确保你的环境中已经安装了所有需要的依赖库&#xff0c;并且…

ChatGPT暂时停止开通puls,可能迎来封号高峰期

前言: 前两日,chat gpt的创始人 San Altman在网上发表了,由于注册的使用量超过了他们的承受能力,为了确保每个人的良好使用体验,chat gpt将暂时停止开通gpt plus。 情况: 前段时间好像出现了官网崩溃的情况,就连api key都受到了影响,所以现在就开始了暂时停止puls的注…

C#学习相关系列之Linq用法---where和select用法(二)

一、select用法 Linq中的select可以便捷使我们的对List中的每一项进行操作&#xff0c;生成新的列表。 var ttlist.select(p>p10); //select括号内为List中的每一项&#xff0c;p10即为对每一项的操作&#xff0c;即对每项都加10生成新的List 用法实例&#xff1a; 1、la…

机器学习中的独立和同分布 (IID):假设和影响

一、介绍 在机器学习中&#xff0c;独立和同分布 &#xff08;IID&#xff09; 的概念在数据分析、模型训练和评估的各个方面都起着至关重要的作用。IID 假设是确保许多机器学习算法和统计技术的可靠性和有效性的基础。本文探讨了 IID 在机器学习中的重要性、其假设及其对模型开…

Linux输入设备应用编程(触摸屏获取坐标信息)

上一章学习了开发板外接键盘并获取键盘的的输入 Linux输入设备应用编程&#xff08;键盘&#xff0c;按键&#xff09;-CSDN博客 本章编写触摸屏应用程序&#xff0c;获取触摸屏的坐标信息并将其打印出来 一 触摸屏数据分析&#xff08;触摸&#xff0c;点击&#xff0c;松开…

CI/CD相关概念学习

文章目录 CI/CD相关概念学习前言CI/CD相关概念介绍集成地狱持续集成持续交付持续部署Devops CI/CD相关应用介绍JenkinsTekton PipelinesSpinnakerTravis CIGoCD CI/CD相关概念学习 前言 本文主要是介绍一些 CI/CD 相关的概念&#xff0c;通过阅读本文你将快速了解 CI/CD 是什么…

python时间变化与字符串替换技术及读JSON文件等实践笔记

1. 需求描述 根据预测出结果发出指令的秒级时间&#xff0c;使用时间戳&#xff0c;也就是设定时间&#xff08;字符串&#xff09;转为数字时间戳。时间计算转换过程中&#xff0c;出现单个整数&#xff08;例如8点&#xff09;&#xff0c;按字符串格式补齐两位“08”。字符…

quickapp_快应用_tabBar

tabBar 配置项中配置tabBar(版本兼容)使用tabs组件配置tabBar语法示例问题-切换tab没有反应问题-数据渲染问题解决优化 问题-tab的动态配置 第三方组件tabbar 一般首页都会显示几个tab用于进行页面切换&#xff0c;以下是几种tab配置方式。 配置项中配置tabBar(版本兼容) 在m…