面试官:请分析一条SQL语句的执行

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
日志服务 SLS,月写入数据量 50GB 1个月
简介: 我感到在对全局了解不够清晰的时候,去深究一个知识点往往会事倍功半。所以打算通过这篇文章,分析SQL语句从头到尾的执行,串连一下MySQL当中的基础知识点。
关注公众号【程序员白泽】,带你走进一个不一样的程序员/学生党

前言

最近一直在写《手撕MySQL系列》文章,我发现自己的切入点有一些问题,虽尝试深入探究MySQL中的一些关键特性,但对于MySQL的知识掌握不太能够形成较好的体系化的知识网络。我感到在对全局了解不够清晰的时候,去深究一个知识点往往会事倍功半。所以打算通过这篇文章,分析SQL语句从头到尾的执行,串连一下MySQL当中的基础知识点。

当然希望借助一篇文章深入剖析MySQL所有的关键特性是不够的,后面也会继续更新《手撕MySQL》系列,只是可能会调整写作的切入角度,尽可能帮助阅读文章的同学建立体系化的知识网络

基础架构

image-20220408190837974

  1. 客户端:Navicat是一款我们常用的数据库操作工具,通过该数据库客户端软件我们去建立数据库连接,输入SQL语句并提交执行命令。
  2. 服务端Server:首先要明确的是,客户端运行时是一个进程,那么发起连接,执行SQL等命令都有一个接收进程,那就是MySQL的服务端进程 (你刚开始学MySQL时总是听到启动MySQL服务就是指这个进程) ,借助MySQL服务端进程去处理所有从客户端发起的数据库操作,并且最后将改动持久化到数据库磁盘文件上。
  3. 存储引擎内存池:将MySQL服务端拆解成两个部分时因为存储引擎是针对表而言的,对于不同的表可以选择不同的存储引擎,并利用其相应的特性满足对应的业务需求,我们在创建一张表的时候最后写的engine=innodb就是在指定选择的存储引擎,从5.5版本开始,如果不指定存储引擎,则默认使用InnoDB
  4. 通用服务层:这一部分包含了MySQL中的通用核心服务,所有跨存储引擎的功能都在这里,包括连接器、查询缓存、分析器、优化器、执行器、以及内置的函数表达式等等 (图上还有很多没画出来,后面的文章中也会逐渐补充进来)
  5. 数据库磁盘文件:这一部分的作用是持久化数据库数据,服务端Server终究是一个运行的进程,所有的数据都是临时存放在内存当中,而我们最终的目的自然是维护一份永久的数据库文件。 (当然不是说内存就不重要,相反,因为客户端操作数据库必然会频繁修改磁盘上的文件,想要操作数据就得先将磁盘中的目标文件页读到内存中,在内存中操作完成之后,再把改动之后的数据页刷新回磁盘,而磁盘IO性能较低,合理使用内存或者说缓存的技术可以减少磁盘IO次数,大大提高数据库访问的性能,这一部分将在后面逐渐介绍)

一条查询语句

接下来分析下面这条查询语句的执行过程

select * from T where id = 1
  1. 连接器:首先通过客户端如Navicat连接到这个数据库服务进程 (需要输入目标服务器的IP、端口、用户名、密码) ,而负责与建立连接的就是连接器,负责校验用户名密码,以及获取对应权限。
  2. 查询缓存:以key-value形式存储一条查询语句对应的结果,如果当前输入的SQL在查询缓存中,可以直接返回查询结果而不用重复执行,但是查询缓存在MySQL8.0被废弃,原因是一条查询缓存对应的表如果发生了修改,则针对这个表的查询缓存都将失效而被清除,如果表更新频率比较高,则会大大提高查询缓存的失效可能,缓存利用率很低,还会额外占用内存开销。
  3. 分析器:分析器只是一个概称,它的工作是将SQL语句通过解析器成一颗对应的解析树,然后交由预处理器进一步检查解析树的各个部分的语法是否合法,包括对应的表、字段是否存在、名称是否合法等,不合法就抛出错误,通过分析器分析之后合法,则再交由优化器进行分析
  4. 优化器:这里先简单理解成一条查询语句涉及的表可能在不同的字段上建立了多个索引,也有可能涉及多个表,这里需要优化器去分析得到一个最优的执行方案(效率最高),比如选择走哪个索引,选择多个表之间的连接顺序等
  5. 执行器:校验是否有权限访问SQL中涉及的表,然后配合对应的存储引擎,根据优化器给出的执行方案执行一个SQL,最后返回查询结果。

一条更新语句

看到这里你大概对MySQL如何执行一条查询语句的执行流程大概有了概念,也初步熟悉了其中会涉及到的一些 “功能组件” ,但你还不太满足,MySQL的redo log、bin log在哪呢?面试老爱问了! (undo log这里先不提)接下来分析下面这条更新语句的执行过程

update T set a = 0 where id = 1

image-20220408190837974

与查询语句相同,执行更新语句也要经过上面那张图中从连接器到执行器的部分,这里我再放一下。区别在于更新表对数据库磁盘文件造成了变更,而查询语句没有。而且前面也提到,MySQL通过一些机制合理减少磁盘IO次数,提升数据库访问性能与可靠性。这里就要介绍一下更新操作中涉及到的两种物理日志文件,redo logbin log(MySQL服务端内存中也有对应着的日志缓存)。

redo log

redo log是InnoDB引擎持有的日志文件(bin log是MySQL通用层的日志文件),也就是说一张表选择InnoDB引擎,在执行更新语句时会同时产生redo和bin两种物理日志文件。 这里先介绍redo log:

前面说了,MySQL通过一些机制可以减少磁盘IO,以及提升数据库可靠性。redo log功不可没,在InnoDB引擎内存池中,维护着redo log

具体来说,在执行上面那条更新语句的时候,InnoDB引擎会将涉及到的记录读取到内存中(只有对应记录在内存中才可以开始更新),更新对应这条记录的内存(此时磁盘中的这条记录还没更新,但内存中更新了),再将更新记录到redo log缓存。之后redo log缓存会按照一些规则刷新到磁盘文件中的redo log物理文件。而那些在内存中与物理磁盘不同的记录称之为脏页,脏页会通过一种叫checkpoint的规则去刷新到磁盘上(此时才是真的完成了更新)。

上面大概描述了InnoDB引擎在更新时选择先将更新日志记录下来,再最后修改磁盘(称之为WAL技术—Write-Ahead Logging),这样设计的作用是即使MySQL服务因为意外宕机时,之前的更新记录依旧保存在redo log磁盘文件中 (如果只是单纯依赖redo log缓存,则掉电后会遗失这部分数据,而不使用redo log则每次更新表的操作就得进行磁盘IO,无法优化,性能低下)

从上面我们可以看到重做日志文件侧重于数据库崩溃时的数据恢复,以及涉及脏页的刷新时机,因此InnoDB引擎对于redo log文件的设计是循环写的,并没有给予无限的增长空间,如下图,如果有两个大小为1G的redo log磁盘文件,则随着redo log缓存逐渐刷新到磁盘上,这两个文件会逐渐被填满,并循环覆盖。因此如果即将被覆盖的redo log代表的操作(脏页)还没有刷新到磁盘,则会触发checkpoint,刷新这些脏页,只要磁盘完成修改,则对应的redo log磁盘文件可以被覆盖掉(这是checkpoint的某一个触发条件)。

image-20220408195952740

bin log

bin log是很容易拿来与redo log进行比较的,它是MySQL通用层实现的,记录对数据库表的变更操作,不记录查询,而且由于历史原因,InnoDB引擎是后来出现的,bin log被用于日志归档(较长时间跨度的数据恢复/主从复制),而redo log则侧重于崩溃时保留改动的数据。

下面给出几个bin log与redo log的不同点:

  1. redo log是物理日志,记录的是某条记录发生了什么改动;bin log是逻辑日志,记录的是语句的原始逻辑(bin log也可以选择记录日志的模式)。
  2. bin log称为归档日志(可能会根据需求保留过去一个月的数据库变更),因此它是追加写入的,没有大小限制;redo log是循环写入,有大小限制。(这主要是因为侧重的功能不同)
  3. redo log是InnoDB引擎层的,bin log是MySQL通用层的。

二阶段提交

步骤

那么对于使用InnoDB的表,执行上面那条update语句时,redo logbin log是如何配合工作的呢?步骤简化之后如下:

  1. 判断表T的id=1的记录是否在内存中
  2. 不在则先从磁盘读入内存
  3. 在内存中,将id=1的这条记录的a字段修改为0
  4. 将修改操作写入磁盘redo log,此时redo log处于prepare状态
  5. 将修改操作写入磁盘bin log
  6. 提交事物,将redo log修改为commit状态

二阶段提交的由来是redo log的状态经历了从preparecommit两个阶段的变化,而二阶段提交的目的就是为了使bin logredo log在配合使用时,在遇到宕机等情况时数据恢复能保持逻辑上的一致。

分析

如果不使用两阶段提交,只有单一的修改磁盘redo log和磁盘bin log则会有以下两种问题:

  1. 先写bin log,后写redo log,在写入bin log之后,服务器宕机,此时redo log未写入,则本地磁盘中将丢失对于数据的更改(也丢失了修改的脏页),而bin log归档文件中已经写入了修改逻辑,那么用这个bin log进行数据恢复或者主从复制会使得与当前数据库表数据之间出现不同。
  2. 先写redo log,后写bin log,在写入redo log之后,服务器宕机,此时bin log未写入,则本地磁盘中将保留对数据的修改,但是bin log归档文件中没有记录这个修改逻辑。那么用这个bin log进行数据恢复或者主从复制依旧会使得与当前数据库表数据之间出现不同。

使用两阶段可以通过redo log的状态判断本次修改是否在bin log和redo log上都完成了记录,结合回滚和补充提交机制,从而确保数据在两种日志文件中的逻辑一致性。

关注公众号【程序员白泽】,带你走进一个不一样的程序员/学生党,公众号回复【简历】可以获得我正在使用的简历模板,平时也会同步更新文章。希望大家都能收获心仪的offer~
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
23小时前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
1月前
|
SQL 缓存 监控
大厂面试高频:4 大性能优化策略(数据库、SQL、JVM等)
本文详细解析了数据库、缓存、异步处理和Web性能优化四大策略,系统性能优化必知必备,大厂面试高频。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:4 大性能优化策略(数据库、SQL、JVM等)
|
2月前
|
SQL 存储 数据可视化
手机短信SQL分析技巧与方法
在手机短信应用中,SQL分析扮演着至关重要的角色
|
4月前
|
机器学习/深度学习 算法 数据中心
【机器学习】面试问答:PCA算法介绍?PCA算法过程?PCA为什么要中心化处理?PCA为什么要做正交变化?PCA与线性判别分析LDA降维的区别?
本文介绍了主成分分析(PCA)算法,包括PCA的基本概念、算法过程、中心化处理的必要性、正交变换的目的,以及PCA与线性判别分析(LDA)在降维上的区别。
108 4
|
4月前
|
前端开发 Java JSON
Struts 2携手AngularJS与React:探索企业级后端与现代前端框架的完美融合之道
【8月更文挑战第31天】随着Web应用复杂性的提升,前端技术日新月异。AngularJS和React作为主流前端框架,凭借强大的数据绑定和组件化能力,显著提升了开发动态及交互式Web应用的效率。同时,Struts 2 以其出色的性能和丰富的功能,成为众多Java开发者构建企业级应用的首选后端框架。本文探讨了如何将 Struts 2 与 AngularJS 和 React 整合,以充分发挥前后端各自优势,构建更强大、灵活的 Web 应用。
65 0
|
4月前
|
SQL 数据采集 数据挖掘
为什么要使用 SQL 函数?详尽分析
【8月更文挑战第31天】
62 0
|
4月前
|
SQL 数据采集 算法
【电商数据分析利器】SQL实战项目大揭秘:手把手教你构建用户行为分析系统,从数据建模到精准营销的全方位指南!
【8月更文挑战第31天】随着电商行业的快速发展,用户行为分析的重要性日益凸显。本实战项目将指导你使用 SQL 构建电商平台用户行为分析系统,涵盖数据建模、采集、处理与分析等环节。文章详细介绍了数据库设计、测试数据插入及多种行为分析方法,如购买频次统计、商品销售排名、用户活跃时间段分析和留存率计算,帮助电商企业深入了解用户行为并优化业务策略。通过这些步骤,你将掌握利用 SQL 进行大数据分析的关键技术。
246 0
|
4月前
|
SQL 数据挖掘 BI
【超实用技巧】解锁SQL聚合函数的奥秘:从基础COUNT到高级多表分析,带你轻松玩转数据统计与挖掘的全过程!
【8月更文挑战第31天】SQL聚合函数是进行数据统计分析的强大工具,可轻松计算平均值、求和及查找极值等。本文通过具体示例,展示如何利用这些函数对`sales`表进行统计分析,包括使用`COUNT()`、`SUM()`、`AVG()`、`MIN()`、`MAX()`等函数,并结合`GROUP BY`和`HAVING`子句实现更复杂的数据挖掘需求。通过这些实践,你将学会如何高效地应用SQL聚合函数解决实际问题。
63 0
|
4月前
|
网络协议 NoSQL 网络安全
【Azure 应用服务】由Web App“无法连接数据库”而逐步分析到解析内网地址的办法(SQL和Redis开启private endpoint,只能通过内网访问,无法从公网访问的情况下)
【Azure 应用服务】由Web App“无法连接数据库”而逐步分析到解析内网地址的办法(SQL和Redis开启private endpoint,只能通过内网访问,无法从公网访问的情况下)
|
5月前
|
存储 SQL 索引
面试题MySQL问题之使用SQL语句创建一个索引如何解决
面试题MySQL问题之使用SQL语句创建一个索引如何解决
54 1