结合mysql 架构分析SQL查询语句和更新语句的执行

一:基础架构

mysql分为Server层和存储引擎层

Server层

涵盖了大多数mysql的核心服务功能,以及所有内置的函数(例如日期、加密、数学等函数),所有跨存储引擎的操作都在Server层实现:存储过程、触发器、视图等

  • 连接器

    • 连接器主要负责建立连接、进行权限验证、维持和管理连接,

    • 连接完成后,如果没有后续操作,这个链接就处于空闲状态(sleep)

思考

①为什么推荐使用长连接?

  • 建立连接的过程通常比较复杂

②推荐使用长连接,但如何解决长连接内存占用太大问题?

  • 定期断开长连接

  • MySQL 5.7 及以上,可以在每次执行一个比较大的操作后,通过执行 mysql_reset_connection来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态。

  • 查询缓存

    • 只要对表进行更新,那么这个表的所有缓存结果都会被清空

    • mysql 8.0之后就不再支持查询缓存

    • Mysql拿到一个查询请求后,会去看之前执行过的以key-value对形式缓存在内存中的执行结果,key就是执行语句,value就是执行结果

    • 如果存在缓存,就直接返回,不存在会继续执行后面的操作

    • 不建议使用

思考

①为什么不推荐使用查询缓存?查询缓存适用场景?如何按需使用缓存?

  • 查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空

  • 适用场景:静态表,很长时间才会更新一次。比如,一个系统配置表,那这张表上的查询才适合使用查询缓存

  • mysql8.0以前可以按需使用缓存:select SQL_CACHE * from T where ID=10;(需要将query_cache_type设置成 DEMAND)

query_cache_type=0/OFF:关闭查询缓存。
query_cache_type=1/ON:开启查询缓存。
query_cache_type=2/ DEMAND :当使用 SELECT SQL_CACHE会开启缓存

    • 分析器

      • 词法分析,识别sql语句要进行的操作、用到的表和字符串

      • 语法分析,判断sql语句是否满足mysql的语法规则

    • 优化器

决定使用什么样的索引,如果是连表查询的话要判断连接表的顺序

优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联 (join)的时候,决定各个表的连接顺序
select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;
既可以先从表 t1 里面取出 c=10 的记录的 ID 值,再根据 ID 值关联到表 t2,再判断 t2 里面 d 的值是否等于 20
也可以先从表 t2 里面取出 d=20 的记录的 ID 值,再根据 ID 值关联到 t1,再判断 t1 里面 c 的值是否等于 10
优化器的作用就是决定选择使用哪一个方案
思考

①优化器是怎么选择索引的,有没有可能选择错?

根据扫描行数、是否排序、是否使用临时表、是否回表等

  • 执行器

    • 判断对要操作的表有没有操作权限(读和写)

    • 通过存储引擎的接口,取出所需要的结果数据

思考

①有索引和无索引执行器的执行流程?(以select * from T where ID=10为例)

  • 扫描满足的行与全表扫描再判断的区别(这个过程是执行器调用引擎接口执行的)

ID 字段没有索引
1. 调用 InnoDB 引擎接口取这个表的第一行,判断 ID 值是不是 10,如果不是则跳过,如果是则将这行存在结果集中;
2. 调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。
3. 执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。

 

ID 字段有索引
1.第一次调用的是“取满足条件的第一行”这个接口
2.之后循环取“满足条件的下一行”这个接口,接口都是引擎中已经定义好的

存储引擎层

负责数据的存储和提取,架构模式是插件式的。支持InnoDb、MyIsam等,从mysql5.5.5版本后,InnoDB成为Mysql默认的存储引擎

  1. 客户端:Navicat是常用的数据库操作工具,通过该数据库客户端软件我们去建立数据库连接,输入SQL语句并提交执行命令。

  2. 服务端Server:首先要明确的是,客户端运行时是一个进程,那么发起连接,执行SQL等命令都有一个接收进程,那就是MySQL的服务端进程 (启动MySQL服务就是指这个进程) ,借助MySQL服务端进程去处理所有从客户端发起的数据库操作,并且最后将改动持久化到数据库磁盘文件上。

  3. 存储引擎内存池:将MySQL服务端拆解成两个部分是因为存储引擎是针对表而言的,对于不同的表可以选择不同的存储引擎,并利用其相应的特性满足对应的业务需求

  4. 通用服务层:所有跨存储引擎的功能都在这里,包括连接器、查询缓存、分析器、优化器、执行器、以及内置的函数表达式等等,包含了MySQL中的通用核心服务。

  5. 数据库磁盘文件:持久化数据库数据,服务端Server终究是一个运行的进程,所有的数据都是临时存放在内存当中,而我们最终的目的是维护一份永久的数据库文件。 (客户端操作数据库必然会频繁修改磁盘上的文件,想要操作数据就得先将磁盘中的目标文件页读到内存中,在内存中操作完成之后,再把改动之后的数据页刷新回磁盘,而磁盘IO性能较低,合理使用内存或者说缓存的技术可以减少磁盘IO次数,大大提高数据库访问的性能) 。

InnoDB与MyISAM详细比较参照下表

  MyISAM InnoDB
构成上区别

每个MyISAM在磁盘上存储成三个文件。文件名为表名,扩展名为文件类型。

.frm 文件存储表定义;
.MYD(MYData) 数据文件的扩展名;
.MYI(MYIndex) 索引文件的扩展名。

基于磁盘的资源是InnoDB表空间数据文件和它的日志文件,InnoDB 表的大小只受限于操作系统文件的大小,一般为 2GB
事务处理方面 MyISAM类型的表强调的是性能,其执行速度比InnoDB类型更快,但是不提供事务支持。

InnoDB提供事务支持事务,外部键等高级数据库功能。

表级锁

行级锁

InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如update table set num=1 where name like “%aaa%”

select、insert、update、delete操作 如果执行大量的 SELECT,MyISAM 是更好的选择。

1.如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表。

2.DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。

3.LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。

对于AUTO_INCREMENT类型的字段 必须包含只有该字段的索引 可以和其他字段一起建立联合索引
    InnoDB不支持FULLTEXT类型的索引。
  MyISAM类型的二进制数据文件可以在不同操作系统中迁移  

二:查询语句

查询语句的执行过程

select * from T where id = 100
  1. 连接器:首先通过客户端如Navicat连接,输入目标服务器的IP、端口、用户名、密码,到这个数据库服务进程 ,而负责与建立连接的就是连接器,负责校验用户名密码,以及获取对应权限。

  2. 查询缓存:以key-value形式存储一条查询语句对应的结果,如果当前输入的SQL在查询缓存中,可以直接返回查询结果而不用重复执行,但是查询缓存在MySQL8.0被废弃,原因是一条查询缓存对应的表如果发生了修改,则针对这个表的查询缓存都将失效而被清除,如果表更新频率比较高,则会大大提高查询缓存的失效可能,缓存利用率很低,还会额外占用内存开销。

  3. 分析器:分析器只是一个概称,它的工作是将SQL语句通过解析器成一颗对应的解析树,然后交由预处理器进一步检查解析树的各个部分的语法是否合法,包括对应的表、字段是否存在、名称是否合法等,不合法就抛出错误,通过分析器分析之后合法,则再交由优化器进行分析

  4. 优化器:这里先简单理解成一条查询语句涉及的表可能在不同的字段上建立了多个索引,也有可能涉及多个表,这里需要优化器去分析得到一个最优的执行方案(效率最高),比如选择走哪个索引,选择多个表之间的连接顺序等

  5. 执行器:校验是否有权限访问SQL中涉及的表,然后配合对应的存储引擎,根据优化器给出的执行方案执行一个SQL,最后返回查询结果。

执行器的执行查询语句的流程是什么样的

1.调用 InnoDB引擎接口取这个表的第一行,判断 ID 值是不是 100(即条件是否满足),如果不是则跳过,如果是则将这行存在结果集中;
        2.调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。
        3.执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。

对于有索引的表,执行的逻辑也差不多。第一次调用的是“取满足条件的第一行”这个接口,之后循环取“满足条件的下一行”这个接口,这些接口都是引擎中已经定义好的。

三:更新语句

MySQL的redo log、bin log在哪呢? (undo log这里先不提)

接下来分析下面这条更新语句的执行过程

update T set a = 0 where id = 100

更新语句也要经过从连接器到执行器的部分。区别在于更新表对数据库磁盘文件造成了变更,而查询语句没有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,无法优化,性能低下) 。

从上面我们可以看到,redo log文件侧重于数据库崩溃时的数据恢复,以及涉及脏页的刷新时机,因此InnoDB引擎对于redo log文件的设计是循环写的,并没有给予无限的增长空间.

如下图,如果有两个大小为1G的redo log磁盘文件,则随着redo log缓存逐渐刷新到磁盘上,这两个文件会逐渐被填满,并循环覆盖。因此如果即将被覆盖的redo log代表的操作(脏页)还没有刷新到磁盘,则会触发checkpoint,刷新这些脏页,只要磁盘完成修改,则对应的redo log磁盘文件可以被覆盖掉(这是checkpoint的某一个触发条件)。

bin 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=100的记录是否在内存中

  2. 不在,则先从磁盘读入内存

  3. 在内存中,将id=100的这条记录的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上都完成了记录,结合回滚和补充提交机制,从而确保数据在两种日志文件中的逻辑一致性。

文:一只阿木木

欢迎转发、交流小数据。

结合mysql 架构分析SQL查询语句和更新语句的执行的更多相关文章

  1. Mariadb/MySQL数据库单表查询基本操作及DML语句

    Mariadb/MySQL数据库单表查询基本操作及DML语句 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一数据库及表相关概述 1>.数据库操作 创建数据库: CREATE ...

  2. sql查询,如果有更新时间则按更新时间倒序,没有则按创建时间倒序排列

    原文:sql查询,如果有更新时间则按更新时间倒序,没有则按创建时间倒序排列 ORDER BY IFNULL(update_time,create_time) DESC IFNULL(expr1,exp ...

  3. mysql系列-⼀条SQL查询语句是如何执⾏的?

    ⼀条SQL查询语句是如何执⾏的? ⼤体来说,MySQL 可以分为 Server 层和存储引擎层两部分 Server 层 Server 层包括连接器.查询缓存.分析器.优化器.执⾏器等,涵盖 MySQL ...

  4. mysql explain 分析sql语句

    鉴于最近做的事情,需要解决慢sql的问题,现补充一点sql语句性能分析之explain的使用方式! 综合返回数据情况,分析各个参数,可以了解sql 使用方法:explain  + sql语句 如 :e ...

  5. Mysql explain分析sql语句执行效率

    mysql优化–explain分析sql语句执行效率 Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看SQL语句的执行效 ...

  6. mysql体系结构和sql查询执行过程简析

    一: mysql体系结构 1)Connectors 不同语言与 SQL 的交互 2)Management Serveices & Utilities 系统管理和控制工具 备份和恢复的安全性,复 ...

  7. MySQL架构与SQL执行流程

    MySQL架构设计 下面是一张MySQL的架构图: 上方各个组件的含义如下: Connectors 指的是不同语言中与SQL的交互 Management Serveices & Utiliti ...

  8. mysql 变量定义 sql查询

    SET @idnoStr:='"idNo":"'; SELECT LOCATE(@idnoStr, param_array), LOCATE('",', par ...

  9. Python全栈 MySQL 数据库 (SQL查询、备份、恢复、授权)

    ParisGabriel              每天坚持手写  一天一篇  决定坚持几年 为了梦想为了信仰    开局一张图   今天接着昨天的说   索引有4种:      普通 索引 :ind ...

  10. 三:MySQL系列之SQL查询

    本篇主要介绍使用SQL查询数据库的操作,包括条件查询.排序.聚合函数.分组.分页.连接查询.自关联.子查询等命令操作. 首先我们先创建一个数据库.数据表.插入字段: --------这部分在上篇以及介 ...

随机推荐

  1. Java 表达式执行引擎 jexl

    介绍 JEXL的全称是Java表达式语言(Java Expression Language),简单的说,它可以配合我们的Java程序运算一些简单的表达式. 具体可以识别哪些表达式? 包含最基本的加减乘 ...

  2. SpringBoot集成ShardingSphere分表中间件

    ShardingSphere简介 ShardingSphere 由 JDBC.Proxy 和 Sidecar(规划中)这 3 款既能够独立部署,又支持混合部署配合使用的产品组成. 它们均提供标准化的基 ...

  3. Blazor Server App Cannot find the fallback endpoint specified by route values

    github官方issues中提到的解决方案,CreateBuilder时指定项目绝对路径可以解决. 1 // 指定项目路径,也可以用Assembly.GetCallingAssembly获取 2 c ...

  4. 全网最适合入门的面向对象编程教程:17 类和对象的Python实现-鸭子类型与“file-like object“

    全网最适合入门的面向对象编程教程:17 类和对象的 Python 实现-鸭子类型与"file-like object" 摘要: 本文主要介绍了 Python 中创建自定义类时鸭子类 ...

  5. Nuxt.js 中使用 useHydration 实现数据水合与同步

    title: Nuxt.js 中使用 useHydration 实现数据水合与同步 date: 2024/7/18 updated: 2024/7/18 author: cmdragon excerp ...

  6. Ubuntu16.04升级openssh-9.8p1

    7月1日OpenSSH官方发布安全更新,忙着处理的同时记录一下升级过程. 系统环境 root@NServer:~# cat /proc/version Linux version 3.4.113-su ...

  7. JavaScript实现防抖函数

    什么是防抖?防抖就是避免快速多次点击后执行过多的函数调用,就是本来你点击支付宝支付后不小心在点击一次,导致支付函数被调用了两次,还都执行了,付了两次钱. 防抖函数的思想就是将函数延迟调用,延迟时间内不 ...

  8. typora下载安装以及notepad++下载安装

    notepad++下载安装 找到浏览器输入:notepad或者 https://notepad-plus-plus.org/downloads/ 官网下载即可使用 如果官网崩了,可以在微信公众号:A软 ...

  9. 商业级java开发单体项目环境搭建

    写在开发前,端口经常被战占,windows10用以下命令先查先杀,netstat -aon | findstr "8080" taskkill /F /PID <PID> ...

  10. hbuilderx生成ios证书和上架全教程

    现在很多公司都使用uniapp作为底层框架来开发app应用,而uniapp的开发工具hbuilderx云打包的时候,需要证书和证书profile文件. 假如是ios应用,则还需要上架到appstore ...