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.mfbz.cn/a/239269.html

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

相关文章

IO第二天作业

1.用read write函数实现文件拷贝 程序 #include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h> #include <stdlib.h> #include <string.h>int main(int argc, const char *argv[]){…

孩子还是有一颗网安梦——Bandit通关教程:Level 9 → Level 10

&#x1f575;️‍♂️ 专栏《解密游戏-Bandit》 &#x1f310; 游戏官网&#xff1a; Bandit游戏 &#x1f3ae; 游戏简介&#xff1a; Bandit游戏专为网络安全初学者设计&#xff0c;通过一系列级别挑战玩家&#xff0c;从Level0开始&#xff0c;逐步学习基础命令行和安全概念…

初学编程100个代码,python 基础 详细

本篇文章给大家谈谈初学编程100个代码&#xff0c;以及python 基础 详细&#xff0c;希望对各位有所帮助&#xff0c;不要忘了收藏本站喔。 1.Python标识符 在 Python 里&#xff0c;标识符有字母、数字、下划线组成。 在 Python 中&#xff0c;所有标识符可以包括英文、数字以…

新版Spring Security6.2架构 (二) - Authentication

前言&#xff1a; 书接上文&#xff0c;继续官网的个人翻译和个人理解&#xff0c;有不对的请见谅。第一个篇博客中写到Sevlet appliation的总体架构&#xff0c;本博客是写Sevlet appliation中Authentication的架构&#xff0c;在后面第三篇博客将会写到新版spring security如…

IO流(一)

目录 一.关于IO流 二.字节流 1.FIleOutputStream&#xff08;字节输出流&#xff09; 1.书写步骤&#xff1a; 1.创建字节输出流对象 2.写数据 3.释放资源 2.书写数据的三种方式 3.换行写入数据&#xff1a; 4.续写 2.FileInputStream&#xff08;字节输入流&#xf…

【算法-字符串3】听说KMP很难?进来看这篇:实现strstr(),查找子串

今天&#xff0c;带来KMP算法的讲解。文中不足错漏之处望请斧正&#xff01; 理论基础点这里 今天我们来实现strstr()。 题意转化 在一个字符串mainStr中找另一个字符串subStr。 解决思路 两指针i和j分别在mainStr和subStr中拿取字符尝试匹配 匹配&#xff1a;继续不匹配&…

HTML实现页面

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>工商银行电子汇款单</title> </head> &…

主机访问Android模拟器网络服务方法

0x00 背景 因为公司的一个手机app的开发需求&#xff0c;要尝试链接手机开启的web服务。于是在Android Studio的Android模拟器上尝试连接&#xff0c;发现谷歌给模拟器做了网络限制&#xff0c;不能直接连接。当然这个限制似乎从很久以前就存在了。一直没有注意到。 0x01 And…

回顾【数学基础】找出断层,继续前进, 使用chatGPT学习并解决实际问题:微积分

已经学过的算术、代数、几何。跳过。 从微积分开始 想象一下&#xff0c;你在画一条曲线&#xff0c;或者在一个大草地上奔跑。微积分就是一种数学工具&#xff0c;帮助我们了解这条曲线的形状&#xff0c;或者你奔跑的方式。 微分&#xff08;就像研究曲线上的每一小点&…

SQL基础理论篇(十一):事务隔离

文章目录 简介事务并发时的常见异常什么是脏读&#xff1f;什么是不可重复读&#xff1f;什么是幻读&#xff1f; 事务的常用隔离级别参考文献 简介 之前我们讲过事务的四大特性&#xff0c;即ACID&#xff0c;分别是原子性、一致性、隔离性和持久性。隔离性就是事务的基本特性…

ROBdispatch stage

ROB会跟踪所有pipeline中的指令的状态&#xff1b;一旦ROB中&#xff0c;header指的entry complete了&#xff0c;则该指令可以commit,其architectural state属于visible了&#xff1b;如果header instruction 发生了异常&#xff0c;pipleine需要flush, 在该exception instruc…

Python接口自动化测试 —— Requests库学习

安装&#xff1a; pip install requests 例子&#xff1a; import requests r requests.get(http://www.baidu.com) print r.status_code print type(r) print r.cookies运行程序&#xff0c;得到结果&#xff1a; 运行程序&#xff0c;得到结果&#xff1a; 200 <…

Leetcode—2963.统计好分割方案的数目【困难】

2023每日刷题&#xff08;五十七&#xff09; Leetcode—2963.统计好分割方案的数目 算法思想 参考灵神思路 实现代码 class Solution { public:long long mod 1e97;long long pow(long long x, int cnt) {if(cnt 0) {return 1;}if(cnt 1) {return x % mod;}long long …

css处理 纯英文数据不换行问题 - word-break、word-wrap

问题图 解决 添加 css 样式 word-break: break-all;补充 还有一个 word-wrap 样式&#xff0c;可以看下 参考 &#xff1a; word-wrap: normal 只在允许的断字点换行&#xff08;浏览器保持默认处理&#xff09;。word-wrap: break-word 在长单词或 URL 地址内部进行换行。

书-选择排序法P156

#include<stdio.h> int main(){int b[5]{8,2,6,3,7};int i , j ,k ;for(i0;i<4;i){for(ji1;j<5;j)if(b[i]<b[j]){kb[i];b[i]b[j];b[j]k;} }for(i0;i<5;i)printf("%d ",b[i]); return 0; }选择排序&#xff1a;就是自己跟下一个比较&#xff0c;然后…

Android studio 无法查看源码

Android studio 查看源码时提示 Decompiled .class file,bytecode version:52.0(java 8) 1、检查 buildToolsVersion 2、检查相关资源文件

SPRD Android 13 下拉状态栏菜单添加静音快捷键简单记录

SPRD Android 13 下拉状态栏菜单添加静音快捷键简单记录 需要修改文件具体修改补丁吐槽需要修改文件 frameworks/base/packages/SystemUI/res/values/config.xml frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java frameworks/base…

1844_高边驱动以及低边驱动的选择

Grey 全部学习内容汇总&#xff1a;GitHub - GreyZhang/g_hardware_basic: You should learn some hardware design knowledge in case hardware engineer would ask you to prove your software is right when their hardware design is wrong! 1844_高边驱动以及低边驱动的…

mmpi量表在各企事业单位 入职体检中的应用

mmpi量表主要应用在医院精神科门诊中&#xff0c;用来检测筛查精神类疾病&#xff0c;比如&#xff1a;焦虑抑郁&#xff0c;疑病妄想强迫性、精神分裂、精神病态、社会内向性、癔症&#xff0c;精神衰弱&#xff0c;躁狂等等。 民航&#xff0c;司法&#xff0c;军警&#xf…

创建第一个SpringBoot项目

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 循序渐进学SpringBoot ✨特色专栏&…