一条 SQL 语句是如何执行的
一条 SQL 语句是如何执行的
SQL查询语句
select * from user where ID=10;
MySQL 的基本架构可以分为 Server 层和存储引擎两部分。Server 层又包含连接器、(查询缓存)、分析器、优化器和执行器。
连接器:连接器负责和客户端建立连接、获取权限、维持和管理连接。
查询缓存:建立连接后可以执行 SELECT 语句,执行逻辑来到第二步查询缓存。
MySQL 拿到查询请求后,会先到查询缓存中查看,是不是之前执行过的语句。查询缓存的存储形式是 key-value 形式,key是查询语句,value是查询结果。如果在缓存中则直接返回,不在缓存中则执行后续步骤,将结果放到缓存中。但不建议使用查询缓存,因为只要有对一个表的更新,这个表上的所有查询缓存都会被清空,因此很大的可能是把结果缓存起来之后,还没来的及用,就被清空了,利大于弊。MySQL8.0 彻底删除了查询缓存。
分析器:先进行词法分析在进行语法分析。
- 词法分析:MySQl 要识别出你输入的这条语句里的字符串分别是什么,代表什么。通过 “select” 关键字识别这是一条查询语句,通过 “user” 识别成 “表名 user”。
- 语法分析:语法分析器会根据 MySQL 的语法规则判断你输入的 SQL 语句是否符合 MySQL 的语法规范。
优化器:优化器负责当表里有多个索引的时候决定用哪一个,当语句中有多表关联时选择连接顺序
执行器:判断对要查询的表是否有执行查询的权限,没有返回权限错误,有权限则打开表,执行器根据表的引擎定义,去使用这个引擎提供的接口。
SQL 更新语句
update T set c=c+1 where ID=10;
查询语句走的流程更新语句也会走一遍,不再赘述。不同的是,更新语句执行的过程中会涉及两个重要的日志模块:redo log(重做日志)和 binlog(归档日志)
redo log
redo log 可以使 InnoDB保证即时数据库发生异常重启,之前的记录都不会丢失(crash-safe)
如果每次更新操作都立刻写入磁盘,然后磁盘找到数据进行修改整个过程 IO 成本、查找成本都很高,为了解决这个问题 MySQL 应用了 WAL(Write-Ahead Logging 写前日志)先写日志在写磁盘。
具体来说,当有一条更新记录来的时候,InnoDB 会先把记录写到 redo log里,并更新内存,等到闲时再把操作写回磁盘。
redo log 是固定大小的。从头开始写,写到末尾就又从头开始写。
write pos:当前记录的位置,边写边后移,写到末尾则从头开始。
checkpoint:当前要擦除的位置,也是向后推并循环的。
write pos 和 checkpoint 之间空着的部分,可以用来记录新的操作,当 write pos 追上 checkpoint 重合时,这时就不能继续执行更新操作了,要停下来擦除一些记录,将 checkpoint 向后推。
binlog
redo log 是InnoDB 引擎特有的日志,binlog 是 MySQL 的日志,没有 crash-safe。
两种日志的不同点:
- redo log 是 InnoDB 引擎特有的,binlog 是 MySQL 的 Server 层实现的,所有的引擎都可以用。
- redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑如“给 ID=10 这一行的 c 字段加 1”。
- redo log 是循环写的,binlog 是追加写的,写满了不会覆盖,切换到下一个继续写。
update 语句的内部流程
update T set c=c+1 where ID=10;
- 执行器先找引擎取到 ID=10 这一行,ID是主键,引擎直接用搜索树找到这一行。如果 ID=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则需要先从磁盘读入内存再返回给执行器。
- 执行器拿到这行数据后,执行修改操作,得到新的一行数据,再调用引擎接口写回这行数据。
- 引擎将这行数据更新到内存中,同时将这个更新操作记录到 redo log 中,此时 redo log 处于 prepare 状态,然后告知执行器,执行完了,可以随时提交事物。
- 执行器生成这个操作的 binlog,并把binlog写入磁盘。
- 执行器调用引擎接口提交事务,并把 redo log 改成 commit 状态,更新完成。
两阶段提交
假设要把c=0更新成c=1
先写 redo log 再写 binlog
假设 redo log 写完了 binlog 还没写,这时候数据库挂了,重启后进行恢复,这时候通过redo log恢复后 c仍然是1。
但binlog并没有写完就crash了,因此binlog里并没有这条语句,日后在用binlog进行恢复临时库时就会出现主从库不一致的现象。
先写binlog 再写 redo log
如果在binlog写完之后crash,由于redo log还没写,崩溃恢复以后这个事务无效,所以这一行c的值是0。但是binlog里面已经记录了“把c从0改成1”这个日 志。所以,在之后用binlog来恢复的时候就多了一个事务出来,恢复出来的这一行c的值就是 1,与原库的值不同。
简单说,redo log和binlog都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保
持逻辑上的一致。
一条 SQL 语句是如何执行的的更多相关文章
- 一条SQL语句是如何执行的?--Mysql45讲笔记记录 打卡day1
写在前面的话:回想以前上班的时候,空闲时间还是挺多的,但是都荒废了.如今找工作着实费劲了.但是这段时间在极客时间买了mysql45讲,就好像发现了新大陆一样,这是我认真做笔记的第一天,说实话第一讲我已 ...
- 《Mysql 一条 SQL 语句是如何执行的?》
一:概述 - 首先需要认识一下 Mysql 整体的基础架构 - 二:Mysql 的分层 - MySQL 可以分为 Server 层和存储引擎层两部分 - Server 层 - Server 层包括连 ...
- 腾讯面试:一条SQL语句执行得很慢的原因有哪些?---不看后悔系列
说实话,这个问题可以涉及到 MySQL 的很多核心知识,可以扯出一大堆,就像要考你计算机网络的知识时,问你"输入URL回车之后,究竟发生了什么"一样,看看你能说出多少了. 之前腾讯 ...
- 一条SQL语句执行得很慢的原因有哪些?
说实话,这个问题可以涉及到 MySQL 的很多核心知识,可以扯出一大堆,就像要考你计算机网络的知识时,问你“输入URL回车之后,究竟发生了什么”一样,看看你能说出多少了. 之前腾讯面试的实话,也问到这 ...
- 一条SQL语句在MySQL中如何执行的
本篇文章会分析一个 sql 语句在 MySQL 中的执行流程,包括 sql 的查询在 MySQL 内部会怎么流转,sql 语句的更新是怎么完成的. 在分析之前我会先带着你看看 MySQL 的基础架构, ...
- 一条SQL语句执行得很慢的原因有哪些?(转)
一条 SQL 语句执行的很慢,那是每次执行都很慢呢?还是大多数情况下是正常的,偶尔出现很慢呢?所以我觉得,我们还得分以下两种情况来讨论. 1.大多数情况是正常的,只是偶尔会出现很慢的情况. 2.在数据 ...
- 一条SQL语句在MySQL中是如何执行的
概览 本篇文章会分析下一个sql语句在mysql中的执行流程,包括sql的查询在mysql内部会怎么流转,sql语句的更新是怎么完成的. 一.mysql架构分析 mysql主要分为Server层和存储 ...
- 一条 SQL 语句在 MySQL 中如何执行的
一 MySQL 基础架构分析 1.1 MySQL 基本架构概览 下图是 MySQL 的一个简要架构图,从下图你可以很清晰的看到用户的 SQL 语句在 MySQL 内部是如何执行的. 先简单介绍一下下图 ...
- 一条SQL语句执行得很慢的原因有哪些
说实话,这个问题可以涉及到 MySQL 的很多核心知识,可以扯出一大堆,就像要考你计算机网络的知识时,问你"输入URL回车之后,究竟发生了什么"一样,看看你能说出多少了. 之前腾讯 ...
随机推荐
- 如何基于 ZEGO SDK 实现 Windows 一对一音视频聊天应用
互联网发展至今,实时视频和语音通话越来越被大众所依赖. 今天,我们将会继续介绍如何基于ZEGO SDK实现音视频通话功能,前两篇文章分别介绍了Android,Flutter平台的实现方式,感兴趣的小伙 ...
- Spring 源码 (2)Spring IOC 容器 前戏准备工作
Spring 最重要的方法refresh方法 根据上一篇文章 https://www.cnblogs.com/redwinter/p/16141285.html Spring Bean IOC 的创建 ...
- 罗马数字转整数,Java执行时间超过100%用户的写法
执行用时:2 ms, 在所有 Java 提交中击败了100.00%的用户 题目 https://leetcode-cn.com/problems/roman-to-integer 罗马数字包含以下七种 ...
- python-django搭建页面步骤
一.配置环境1.file>>New project 创建文件名,配置python.exe执行路径2.setting.py配置①建立static文件夹,最后一行添加STATICFILES_D ...
- Java 线程安全 与 锁
Java 线程安全 与 锁 多线程内存模型 线程私有栈内存 每个线程 私有的内存区域 进程公有堆内存 同一个进程 共有的内存区域 为什么会有线程安全问题? 多个线程同时具有对同一资源的操作权限,又发生 ...
- Vue 学习之路(一)- 创建脚手架并创建项目
安装脚手架 命令 npm install -g @vue/cli 打开 cmd 窗口输入以上命令.当出现以下界面即表示安装完成. 查看已安装脚手架版本 命令 vue -V 在 cmd 窗口输入以上命令 ...
- Kubernetes容器之间的通信浅谈
公众号关注 「开源Linux」 回复「学习」,有我为您特别筛选的学习资料~ 作者: Matt Zand 和 Jim Sullivan 译者: 穿过生命散发芬芳F Kubernetes是一个容器化的解决 ...
- 老生常谈系列之Aop--Spring Aop源码解析(二)
老生常谈系列之Aop--Spring Aop源码解析(二) 前言 上一篇文章老生常谈系列之Aop--Spring Aop源码解析(一)已经介绍完Spring Aop获取advice切面增强方法的逻辑, ...
- Android添加背景图片和设置app图标
Android添加背景图片和设置app图标 Android 添加背景图片 第一步:找到你要当做背景的图片,并下载下来 第二步:将图片复制到app->res->mipmap文件夹下 第三步: ...
- gogin web框架部署学习
首先去git上面找了一个gin框架拿来学习gin web开发: flipped-aurora/gin-vue-admin: 基于vite+vue3+gin搭建的开发基础平台(已完成setup语法糖版本 ...