看了非常多 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. SpringBoot技术栈搭建个人博客【前台开发/项目总结】

    前言:写前台真的是我不擅长的东西...所以学习和写了很久很久...前台页面大概开发了两天半就开发好了,采用的静态的html和bootstrap来写,写后台的时候纠结住了...怎么说呢,写页面真的是头疼 ...

  2. Spring Boot配置拦截器及实现跨域访问

    拦截器功能强大,能够深入方法前后,常应用于日志记录.权限检查和性能检测等,几乎是项目中不可或缺的一部分,本文就来实现Spring Boot自定义拦截器的配置. 理论指导 问:Spring Boot怎么 ...

  3. MariaDB Galera集群部署--技术流ken

    Galera集群介绍 MariaDB集群是MariaDB同步多主机集群.它仅支持XtraDB/ InnoDB存储引擎. 主要功能 同步复制 真正的multi-master,即所有节点可以同时读写数据库 ...

  4. JS 数组、对象的深拷贝

    博客地址:https://ainyi.com/72 JavaScript 程序中,对于简单的数字.字符串可以通过 = 赋值拷贝 但是对于数组.对象.对象数组的拷贝,就有浅拷贝和深拷贝之分 浅拷贝就是当 ...

  5. 树莓派SSH连接快速教程

    树莓派系统一般都默认自带ssh 1.首先检查是否安装ssh没 dpkg - l | grep openssh 如果出现几个openssh-xxx,说明你已经安装了 如果没有 2.SSH服务安装 sud ...

  6. DSAPI+DS控件库 Windows7风格控件演示

    效果图 部分代码 DSAPI.Win7特性.任务栏特效.初始化() '这句非常重要,很多对任务栏特性的操作都需要先初始化 DSAPI.Win7特性.设置任务栏窗口缩略图(Me, My.Resource ...

  7. tomcat,httpd 日志格式说明

    tomcat 日志说明 配置文件server.xml 默认日志格式为 pattern="%h %l %u %t "%r" %s %b" 推荐使用 pattern ...

  8. python自定义pi函数的代码

    下边内容是关于python自定义pi函数的内容. def pi(): # Compute digits of Pi. # Algorithm due to LGLT Meertens. k, a, b ...

  9. ElasticSearch-6.3.2 linux 安装

    在linux 系统安装ElasticSearch-6.3.2最新版本,也适合6.x 系列版本做参考 前提先在linux 安装好jdk1.8 创建用户 从5.0开始,ElasticSearch 安全级别 ...

  10. 智能指针std::unique_ptr

    std::unique_ptr 1.特性 1) 任意时刻只能由一个unique_ptr指向某个对象,指针销毁时,指向的对象也会被删除(通过内置删除器,通过调用析构函数实现删除对象) 2)禁止拷贝和赋值 ...