InnoDB在SQL查询中的关键功能和优化策略

文章目录

  • 前言
  • 存储引擎介绍
    • 存储引擎是干嘛的
    • InnoDB的体系结构
  • InnoDB的查询操作
  • InnoDB的查询原理
    • 引入 Buffer Pool
    • 引入数据页
    • Buffer Pool 的结构
    • 数据页的加载
    • Buffer Pool 的管理
    • Buffer Pool 的优化
  • 总结

前言

通过上篇文章《MySQL的体系结构与SQL的执行流程》了解了SQL语句的执行流程以及MySQL体系结构中「连接器」、「SQL接口」「解析器」、「优化器」、「执行器」的功能以及在整个流程中的作用。不过上篇文章留了个尾巴,在执行器调用存储引擎后,存储引擎内部做了什么事没有进一步说明,本文会对此展开介绍,使得我们对SQL整体的执行流程有更加清晰的认识。

存储引擎介绍

存储引擎是干嘛的

先了解下存储引擎是干什么的。

在MySQL的体系结构中,存储引擎是负责和磁盘交互的,当执行一条SQL语句,最终是通过存储引擎获取结果,不论是查询语句、插入语句还是更新语句,所以存储引擎是用来查询、存储、管理数据的。

在MySQL中,存储引擎是可插拔的,可以根据需求卸载或安装存储引擎。现在MySQL支持很多种存储引擎,在5.5版本后InnoDB被设置为默认的存储引擎,所以本文围绕InnoDB展开说明。下图可以看到可替代的存储引擎。

在这里插入图片描述

InnoDB的体系结构

还是老样子,想知道一个系统有什么功能,先了解一下它的体系结构,然后了解每个部分在整个系统中起到什么作用。这里贴一张官网上5.7版本和8.0版本的InnoDB存储引擎结构。

在这里插入图片描述

两个版本最大的区别就是把系统表空间的几个文件摘了出来,这里不展开说明。接下来看一下InnoDB存储引擎在接收到「执行器」的调用请求后做了什么事吧。

InnoDB的查询操作

通过结构图可以看到InnoDB存储引擎有两部分内容,一个是内存结构,另一个是物理结构。很显然,当InnoDB收到一个查询SQL的请求后会有两个操作:

  1. 先去内存中查找有没有符合条件的数据,有,直接将数据返回给执行器。
  2. 如果内存中符合条件的数据,此时需要去磁盘中查找并加载到内存,然后将数据返回给执行器。

没错,在查询数据时InnoDB干的活就是这么简单。当然,我们还是要深入内部了解一下原理。

InnoDB的查询原理

InnoDB是怎么找到符合条件的数据的?

引入 Buffer Pool

这个问题,我们不得不了解一下内存结构中的「Buffer Pool」了。

Buffer Pool」是InnoDB的缓冲区,用来缓存数据页的(结构图中的一个小方块就代表缓存的一个数据页),目的就是为了避免频繁的I/O操作,用来提高效率的。

什么是数据页?

引入数据页

在数据库中,每一行记录落到磁盘上都是按照某种格式存储的,InnoDB引擎是按照自己的「行格式」进行存储的。如果每一次存储和读取一行记录都要和磁盘交互(也就是一次I/O操作),毋庸置疑,对于MySQL这样的存储级别的数据库来说,效率是非常低的。

所以,InnoDB是按照「数据页」为单位和磁盘交互,一页默认大小是16KB,每次I/O操作可以存储或读取很多行数据,这样可以大大减少I/O次数,从而提高效率。「数据页」大概长这样:

在这里插入图片描述

页中的每一个部分都是逻辑中需要的,比如,通过「页类型」就知道数据页不仅存储了表数据,还有索引数据、Undo Log以及该页属于B+Tree索引上的叶子节点还是非叶子节点。当然,表空间、页号、这些信息就更不用说了。

Buffer Pool 的结构

除了数据页,缓冲区中还有个一区域存储了数据页的元数据,比如表空间、页号、表名称、索引等。元数据可以通过执行SELECT * FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE LIMIT 1\G 查看。例如下图

在这里插入图片描述

存储这些元数据的区域叫法比较多,有叫控制块的,有叫缓存页描述的,这里就暂且叫「控制块」吧。通过控制块,InnoDB可以根据请求的SQL表名、索引快速定位到对应的缓存页上。因为Buffer Pool是一个连续的内存空间,所以控制块和缓存页在Buffer Pool中的结构如下

在这里插入图片描述

了解Buffer Pool后继续往下看是怎么找到符合条件的数据。

数据页的加载

Buffer Pool 初始状态是没有缓存页的,所以当InnoDB第一次接收到查询请求后会去磁盘加载数据页。

数据页是怎么加载的呢?

在「InnoDB Data Dictionary」数据字典中存储了表、列、索引这些元数据以及索引根节点的页号,有了页号就好办了,我们知道InnoDB默认会以ID为主键索引构建一个B+Tree,所以,找到了根节点的页号,其他数据页也都可以找到了。

select * from table1 where id=10为例。InnoDB会先把第一页加载到Buffer Pool中,当然也会维护对应的控制块。然后在页中开始遍历查找id为10的行记录,为了快速定位行数据,数据页中维护了一个最小记录和最大记录以及页目录。当ID不存在最小和最大的范围,就可以直接去加载下一页了,以此类推。

页目录的作用是什么呢?

可以理解成给数据页中的用户数据分了个组,比如ID为1~4为一组,5~8是一组,以此类推。页目录是由一个一个槽组成的,分别指向了每一组的最大记录。如下图,id为10的记录可以直接去第四个槽去查找数据,不需要一行一行遍历查找了。

在这里插入图片描述

至此,InnoDB就找到符合id为10的行记录了,然后将此数据响应给「执行器」。

那如果全表扫描会将所有数据页加载到Buffer Pool吗?容量够吗?

Buffer Pool 的管理

理论上只要内存容量足够大,所有的数据页都能存储在内存中,当然成本太高,容量有限。所以,通常都是将热点数据、访问频繁的数据页缓存起来,这一点InnoDB是如何做的?

InnoDB采用LRU算法将缓存的数据页通过链表的形式存储,很多地方都用到了LRU算法,这里就不过多赘述。总之,当缓冲池容量满了就会移除链表尾部数据,这样就可以确保访问频繁的数据一直在缓冲区了。

Buffer Pool 的优化

为了尽可能的缓存更多的数据页,我们可以通过配置innodb_buffer_pool_size,将缓冲区设置尽可能的大。相关命令如下

-- 查看当前缓冲区大小
SELECT @@innodb_buffer_pool_size;
-- 在线设置缓冲区大小(2G)
SET GLOBAL innodb_buffer_pool_size=2147483648;

同时我们可以通过命令show global status like '%innodb%wait%';观察Innodb_buffer_pool_wait_free的数量,当这个值大于0时意味着缓冲区没有可用的页了,此时就需要考虑增加缓冲区的大小了。

这也是MySQL优化的一部分,下次面试再被问到MySQL如何优化,不要只知道索引了。关于buffer_pool的优化详见MySQL官网

总结

最后,再通过一张图总结一下在执行器调用存储引擎后,InnoDB做了什么事。

在这里插入图片描述

  1. InnoDB根据SQL请求去Buffer Pool中查找「行数据」。
  2. 为了避免频繁的I/O操作,InnoDB将「行数据」存放在「数据页」中。
  3. 为了快速定位到数据页,Buffer Pool 中还存储了数据页的元数据,可以根据SQL的表、索引快速定位到数据页。
  4. 在Buffer Pool中没有找到数据后去磁盘加载数据页。通过「InnoDB Data Dictionary」可以找到索引的根节点页号并加载对应的数据页。
  5. 将数据页加载到Buffer Pool中开始查找数据,为了快速找到行记录,数据页中还存放了当前页最小记录、最大记录和页目录。
  6. 由于Buffer Pool容量有限,InnoDB采用LRU算法管理缓存的数据页,确保频繁访问的数据页会一直保留,从而减少去磁盘加载的次数,而那些不经常使用的数据页就会被淘汰。
  7. 我们还可以通过观察Buffer Pool的情况从而进行调整。

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

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

相关文章

【LSM tree 】Log-structured merge-tree 一种分层、有序、面向磁盘的数据结构

文章目录 前言基本原理读写流程写流程读流程 写放大、读放大和空间放大优化 前言 LSM Tree 全称是Log-structured merge-tree, 是一种分层,有序,面向磁盘的数据结构。其核心原理是磁盘批量顺序写比随机写性能高很多,可以通过围绕这一原理进行…

代码随想录-刷题第二十三天

669.修剪二叉搜索树 题目链接:669. 修剪二叉搜索树 思路:确定递归函数定义,根据定义去构造二叉搜索树。 class Solution {// 定义:删除 BST 中小于 low 和大于 high 的所有节点,返回结果 BSTpublic TreeNode trimBS…

scala表达式

1.8 表达式(重点) # 语句(statement):一段可执行的代码# 表达式(expression):一段可以被求值的代码,在Scala中一切都是表达式 - 表达式一般是一个语句块,可包含一条或者多条语句,多条语句使用“…

Android BluetoothAdapter 使用(二)

Android BluetoothAdapter 使用(二) 本篇文章主要讲下蓝牙设备的配对. 1: 蓝牙设备列表展示 下 面是蓝牙设备adapter的代码: package com.test.bluetooth;import android.bluetooth.BluetoothDevice; import android.content.Context; import android.view.LayoutInflater;…

算法通关村第十八关 | 青铜 | 回溯

1.回溯 回溯可以视为递归的拓展,有着明确的解题模板。 很大的不同之处是有一个撤销处理结果的操作,但是大框架就是遍历 N 叉树。 回溯主要解决暴力枚举都解决不了的问题。 回溯模板: void backtracking(参数) {if (终止条件) {存放结果;…

金融密钥管理方案:DUKPT

文章目录 DUKPT体系基本密钥KSNBDKIPEKFKTKDEK 资料来源 DUKPT体系 Dukpt(Derived Unique Key Per Transaction)是一种密钥管理方案,旨在提供对称加密密钥的安全生成和管理。它通常用于保护金融交易和其他安全关键的数据传输。Dukpt 最初是为…

Windows删除文件的时候提示有其他程序使用文件,无法删除,如何找到是谁再使用?

在Windows中,当你尝试删除一个文件时,如果系统提示该文件正在被其他程序使用,你可以通过以下步骤找到是哪个程序在使用该文件: 记下文件名:首先,记下无法删除的文件的完整路径和文件名。 使用"资源监…

Linux中的堡垒机搭建以及使用

JumpServer搭建 安装应用包 curl -sSL https://resource.fit2cloud.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash 一路回车即可安装完毕(可根据需求更改) JumpServer的 配置文件路径 /opt/jumpserver/config/config.tx…

【智能家居】九、停车场车牌识别功能点(回调、解耦)

一、翔云 人工智能开放平台(车牌识别) 二、cJSON 库 三、实现代码 四、回调函数 五、人脸识别和车牌识别获取数据的区别 六、异步网络请求和同步网络请求的区别 七、解耦 一、翔云 人工智能开放平台(车牌识别) 翔云 人工智能开放…

Ansible变量是什么?如何实现任务的循环?

Ansible 利用变量存储整个 Ansible 项目文件中可重复使用的值,从而可以简化项目的创建和维护,并减少错误的发生率。在定义Ansible变量时,通常有如下三种范围的变量: global范围:从命令行或Ansible配置中设置的变量&am…

.NET 反射优化的经验分享

比如针对 GetCustomAttributes 通过反射获取属性的优化,以下例子 // dotnet run -c Release -f net7.0 --filter "*" --runtimes net7.0 net8.0public class Tests{public object[] GetCustomAttributes() => typeof(C).GetCustomAttributes(typeof(MyAttribute…

坑爹的奥数(枚举法)

枚举法是一种解决问题的基本方法,它通过列举问题的所有可能情况来找到问题的解。这种方法适用于问题的解空间相对较小,可以通过穷举所有可能的解来找到最优解或满足特定条件的解。 以下是枚举法的一般步骤: 定义问题: 确定问题的…

Cypress安装与使用教程(2)—— 软测大玩家

😏作者简介:博主是一位测试管理者,同时也是一名对外企业兼职讲师。 📡主页地址:【Austin_zhai】 🙆目的与景愿:旨在于能帮助更多的测试行业人员提升软硬技能,分享行业相关最新信息。…

《C++新经典设计模式》之第10章 迭代器模式

《C新经典设计模式》之第10章 迭代器模式 迭代器模式.cpp 迭代器模式.cpp #include <iostream> #include <vector> #include <list> #include <memory> using namespace std;// 遍历容器中的元素 // 迭代器单独实现为类模板&#xff0c;与容器模板解耦…

TypeScript 第三节:变量声明

一、命名规则 TypeScript 变量的命名规则与 JavaScript 一致&#xff0c;具体如下&#xff1a; 变量名必须以字母、下划线或美元符号&#xff08;$&#xff09;开头&#xff1b;变量名可以包含字母、数字、下划线或美元符号&#xff08;$&#xff09;&#xff1b;变量名区分大小…

数据库字段名和sql关键字冲突报错解决方法

1、修改实体类字段映射。注解里加反引号 2、sql字段上加反引号 3、问题解决

synchronized关键字的用法

synchronized关键字的用法 1、class monitor public synchronized static void staticSync()synchronized (ClassMonitor.class)2、this monitor public synchronized void sync()synchronized (this)3、monitor private final Object object new Object(); synchronized (…

class类实现operator==重载

利用 operator实现重载&#xff0c;实现两个类进行比较 1.不带参数的函数 #include <iostream> #include <string> using namespace std;class Person // 1.定义一个类 { public:Person(string name, int age){this->name name;this->age age;…

ue5材质预览界面ue 变黑

发现在5.2和5.1上都有这个bug 原因是开了ray tracing引起的&#xff0c;这个bug真是长时间存在&#xff0c;类似的bug还包括草地上奇怪的影子和地形上的影子等等 解决方法也很简单&#xff0c;就是关闭光追&#xff08;不是…… 就是关闭预览&#xff0c;在材质界面preview sc…

C# WPF上位机开发(会员充值软件)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 在软件开发中&#xff0c;有一种很重要的控件&#xff0c;那就是表格。大家可以想象下&#xff0c;办公软件里面是不是就有一个专门做表格的软件&a…