看了非常多 MySQL 相关的书籍和文章,没有看到过如此优秀的专栏。所以未来一段时间我会梳理读完该专栏的所学所得。

当我们在执行该查询语句的时候我们在干什么

mysql> select * from T where ID=10;

让我们先来看一个架构示意图

MySQL 架构被清晰的分为了两层,服务器层 | 存储引擎层。

服务器层一般用于存放一些可以跨存储引擎执行的功能,Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),还有存储过程、触发器、视图等。

存储引擎层主要是负责数据的存储和提取,它是一个可插拔的状态。目前我们接触最多的肯定是 Innodb 了,我还使用过 PERCONA 的 Tokudb ,也是一个非常高性能支持事务的存储引擎。

下面和文章一样我们来走一遍执行该查询语句会经历哪些操作。

连接器

首先我们 MySQL 客户端,你可以理解为是我们常用于查询的 ORM 发起的连接到 MySQL 的连接器。连接器如图上标识的用于管理连接和进行权限验证。当我们连接上 MySQL 之后如果没有开始查询,我们的连接将会处于 Sleep 状态。如果我们太长时间没有进行任何查询,连接将会被 MySQL 断开。这个时候如果我们使用 ORM 进行请求就会报错了,需要我们重新连接,进行查询。

当然 MySQL 断开这个时间是通过参数控制的,这个参数是 wait_timeout 默认是 8 个小时

mysql> show variables like '%timeout%';
+-----------------------------+----------+
| Variable_name | Value |
+-----------------------------+----------+
| connect_timeout | 10 |
| delayed_insert_timeout | 300 |
| have_statement_timeout | YES |
| innodb_flush_log_at_timeout | 1 |
| innodb_lock_wait_timeout | 50 |
| innodb_rollback_on_timeout | OFF |
| interactive_timeout | 28800 |
| lock_wait_timeout | 31536000 |
| net_read_timeout | 30 |
| net_write_timeout | 60 |
| rpl_stop_slave_timeout | 31536000 |
| slave_net_timeout | 60 |
| wait_timeout | 28800 |
+-----------------------------+----------+

这里我多提一句,我在对比 MySQL 5.6 和 5.7 参数的时候发现多出来一个参数

have_statement_timeout 默认是 YES, 这个参数用于设置 select 查询语句的超时时间特性开启。

可以通过使用语句

56551 rows in set (0.11 sec)

mysql> SELECT /*+ MAX_EXECUTION_TIME(100) */ * FROM ad_day_yxs1812_pay_detail;
ERROR 3024 (HY000): Query execution was interrupted, maximum statement execution time exceeded

来设置一个最大的查询时间,如果查询时间超过这个时间则会报错。可以看到查询这56551 需要 0.11 sec 也就是 110 ms 我设置了 100ms 的查询时间所以没有办法得到结果就被打断了。

查询缓存

建立完连接之后就会走到查询缓存这一步,其实这可能是 MySQL 最没用的特性之一,查询缓存失效非常频繁,只要有数据发生更新,查询缓存就会失效。

我估摸着这个功能之前可能是用于缓存大量静态数据,但是现在都有 redis 之类的 NoSQL 来 handle 此类情况。所以我也想不到什么场景这个开启会比较有用,有个好消息是 MySQL 官方在 8.0 的时候彻底删除了该功能。

分析器

分析器负责把你的语句进行一些词法分析,如果你的语法有错误将会抛出错误进行提示。分析器处理完语句之后,MySQL 就知道该语句要做什么了。MySQL 的分析器部分分为 词法分析和语法规则。这两个将会生成一颗解析树提供给后面我们要讲到的优化器组件使用。

如果说我们执行

select * from T where k=1

然后没有 k 这一列就会被分析器这一层抛出错误。分析器会帮我们判断表和列是否存在。

优化器

优化器将根据上面的的的解析树生成执行计划。同时优化器还负责选择索引的事情,还有多表关联 join 的时候选择哪个表在前哪个表在后。

执行器

当优化器处理之后就到执行的时候了,开始执行的时候会判断我对该表的操作有没有权限,如果没有会返回权限错误。如果有权限就可以请求引擎的接口查询数据。

对于没有能使用索引的表执行:

1. 调用 InnoDB 引擎接口取这个表的第一行,判断 ID 值是不是 10,如果不是则跳过,如果是则将这行存在结果集中

2. 调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。

3. 执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。

对于有索引的表执行:

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

你会在数据库的慢查询日志中看到一个 rows_examined 的字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加的。

在有些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟 rows_examined 并不是完全相同的。

Reference:

本读书笔记皆来自发布在极客时间的 林晓斌(丁奇)的 MySQL 实战45讲:

极客时间版权所有: https://time.geekbang.org/ 版权所有:

https://time.geekbang.org/column/article/68319

https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_have_statement_timeout

https://www.jiqizhixin.com/articles/2018-12-12-17  MySQL内核源码解读-SQL解析之解析器浅析

【MySQL 读书笔记】当我们在执行该查询语句的时候我们在干什么的更多相关文章

  1. EF5中 执行 sql语句使用Database.ExecuteSqlCommand 返回影响的行数 ; EF5执行sql查询语句 Database.SqlQuery 带返回值

    一: 执行sql语句,返回受影响的行数 在mysql里面,如果没有影响,那么返回行数为  -1 ,sqlserver 里面  还没有测试过 using (var ctx = new MyDbConte ...

  2. Oracle执行SQL查询语句的步骤

    Oracle执行SQL查询语句的步骤 如果用户在SQL*Plus下输入了如下查询语句:SELECT * FROM dept: 查询语句的处理主要包括三个过程:编译(parse).执行(execute) ...

  3. SpringBoot-JPA删除不成功,只执行了查询语句

    今天使用JPA自定义了一个删除方法deleteByUserIdAndCommentId发现并没有删除掉对应的数据,只执行了查询语句 Hibernate: select good0_.id as id1 ...

  4. oracle执行sql查询语句出现错误ORA-00942:表或视图不存在

    情况是这样,A库的用户名和表空间分别为SH , SH 把业务表SH所有数据从A库,导入到B库, 表空间为SH,用户名为SP 在B库里面执行sql查询语句出现错误ORA-00942:表或视图不存在 语句 ...

  5. 【MySQL 读书笔记】当我们在执行更新语句的时候我们在做什么

    该篇其实重点涉及两个日志的使用和处理. 一个是 server 层的 binlog 一个是服务器层的 redolog. 首先还是根据主线来介绍当我们在执行更新语句的时候我们在做什么 Redo Log M ...

  6. 【MySQL 读书笔记】SQL 刷脏页可能造成数据库抖动

    开始今天读书笔记之前我觉得需要回顾一下当我们在更新一条数据的时候做了什么. 因为 WAL 技术的存在,所以当我们执行一条更新语句的时候是先写日志,后写磁盘的.当我们在内存中写入了 redolog 之后 ...

  7. 【MySQL 读书笔记】普通索引和唯一索引应该怎么选择

    通常我们在做这个选择的时候,考虑得最多的应该是如果我们需要让 Database MySQL 来帮助我们从数据库层面过滤掉对应字段的重复数据我们会选择唯一索引,如果没有前者的需求,一般都会使用普通索引. ...

  8. 【MySQL 读书笔记】RR(REPEATABLE-READ)事务隔离详解

    这篇我觉得有点难度,我会更慢的更详细的分析一些 case . MySQL 的默认事务隔离级别和其他几个主流数据库隔离级别不同,他的事务隔离级别是 RR(REPEATABLE-READ) 其他的主流数据 ...

  9. 【MySQL 读书笔记】全局锁 | 表锁 | 行锁

    全局锁 全局锁是针对数据库实例的直接加锁,MySQL 提供了一个加全局锁的方法, Flush tables with read lock 可以使用锁将整个表的增删改操作都锁上其中包括 ddl 语句,只 ...

随机推荐

  1. 数据结构系列(4)之 B 树

    本文将主要讲述另一种树形结构,B 树:B 树是一种多路平衡查找树,但是可以将其理解为是由二叉查找树合并而来:它主要用于在不同存储介质之间查找数据的时候,减少 I/O 次数(因为一次读一个节点,可以读取 ...

  2. JAVA WEB快速入门之通过一个简单的Spring项目了解Spring的核心(AOP、IOC)

    接上篇<JAVA WEB快速入门之从编写一个JSP WEB网站了解JSP WEB网站的基本结构.调试.部署>,通过一个简单的JSP WEB网站了解了JAVA WEB相关的知识,比如:Ser ...

  3. 简易调色盘控件 for .NET(EN)

    By Conmajia Originally posted in 2012 Introduction Simple & fast implementation of a rectangular ...

  4. GOF23种设计模式概括

    GOF23种设计模式分为三种: 创建型模式[工厂方法模式]结构型模式[(类)适配器模式]行为型模式[ 解释器模式,模板方法模式]   创建型模式Creational Patterns抽象工厂模式abs ...

  5. 【esri-loader】帮助文档翻译 part2 用法

    esri-loader怎么用?看完不要太清楚. [未完待续]!!! Q1: 在哪里用? 这是我最疑惑的问题之一,我知道要用esri-loader,肯定是某条js导入语句起作用的,但是你得告诉我写在哪里 ...

  6. 升鲜宝V2.0_生鲜配送行业,对生鲜配送系统开发与实施的深度对比与思考_升鲜宝生鲜配送系统_15382353715_余东升

               升鲜宝V2.0_生鲜配送行业,对生鲜配送系统开发与实施的深度对比与思考_升鲜宝生鲜配送系统_15382353715_余东升 笔者从事生鲜配送软件开发接近10年,前前后后研究了很多 ...

  7. WPF:浅析Dispatcher

    本人文笔差.还是直接上代码吧.(本文假设你对WPF中的Dispatcher有一定的了解) 你觉得下面的代码可以正常执行吗? private void Button_Click(object sende ...

  8. Docker 使用 Dockerfile 构建自己的镜像

    可以使用Dockerfile的配置文件方式进行构建自己的镜像 下面利用docker构建一个Caddy web服务器 构建脚本 Dockerfile有自己的命令,下面使用了一些比较常用的命令,更多的Do ...

  9. Linux shell脚本中shift的用法说明

    shift命令用于对参数的移动(左移),通常用于在不知道传入参数个数的情况下依次遍历每个参数然后进行相应处理(常见于Linux中各种程序的启动脚本). 示例1:依次读取输入的参数并打印参数个数:run ...

  10. eclipse 导入gradle引入多模块项目,引入eclipse后变成了好几个工程

    1.eclipse  导入gradle 项目 ,选择项目文件夹. 2.导入完成后,文档结构变成 ,多个子项目并列了,而且互不依赖,没有层级结构了. 3.点击项目目录,右上角这个小箭头,选择projec ...