2, sql的执行流程和mysql日志系统

Posted 抱走攻城湿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2, sql的执行流程和mysql日志系统相关的知识,希望对你有一定的参考价值。

mysql的基础架构 

    mysql的基础逻辑架构和sql的执行流程图如下两图所示: 

2, sql的执行流程和mysql日志系统

连接器: 

    连接器的主要功能是负责跟客户端建立连接、获取权限、维持和管理连接,连接器在使用的过程中如果该用户的权限改变,是不会马上生效的,因为用户权限是在连接的时候读取的,只能重新连接才可以更新权限,连接器与客户端通信的协议是tcp协议的,连接以后可以使用show processlist;看到执行的连接数。同时在连接时间内超过8小时是sleep的状态会自动断开,这个是mysql默认设置,如果一直不断开,那么这个过程可以叫做一个长连接与之对应的有短连接,短连接是指在执行一条或几条的以后断开连接。当不断使用长连接的时候会占用很大的内存资源,在mysql5.7以后可以使用mysql_reset_connection语句来重新初始化资源。


查询缓存:

        MySQL 拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。之前执行过的语句及其结果可能会以 key-value 对的形式,被直接缓存在内存中。key 是查询的语句,value 是查询的结果。如果你的查询能够直接在这个缓存中找到 key,那么这个 value就会被直接返回给客户端。如果语句不在查询缓存中,就会继续后面的执行阶段。执行完成后,执行结果会被存入查询缓存中。你可以看到,如果查询命中缓存,MySQL 不需要执行后面的复杂操作,就可以直接返回结果,这个效率会很高。但是大多数情况下我会建议你不要使用查询缓存,为什么呢?因为查询缓存往往弊大于利。查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。MySQL 8.0 版本直接将查询缓存的整块功能删掉了


分析器: 

        MySQL分析器由两部分组成,第一部分是用来词法分析扫描字符流,根据构词规则识别单个单词,MySQL使用Flex来生成词法扫描程序在sql/lex.h中定义了MySQL关键字和函数关键字,用两个数组存储;第二部分的功能是语法分析在词法分析的基础上将单词序列组成语法短语,最后生成语法树,提交给优化器语法分析器使用Bison,在sql/sql_yacc.yy中定义了语法规则。然后根据关系代数理论生成语法树。上面解释分析器太官方和复杂了,其实分析器主要是用来进行“词法分析”然后知道这个数据库语句是要干嘛,代表啥意思。这个时候如果分析器分析出这个语句有问题的时候会报错,比如 

ERROR 1064 (42000): You have an error in your SQL syntax


优化器: 

    在分析器分析完了以后知道这个语句是干嘛的时候,接下来是专门用一个优化器进行语句优化,优化器的任务是发现执行SQL查询的最佳方案。大多数查询优化器,包括MySQL的查询优化器,总或多或少地在所有可能的查询评估方案中搜索最佳方案。优化器主要是选择一个最佳的执行方案,执行方案是为了减少开销,提高执行效率。

MySQL的优化器是一个非常复杂的部件,它使用了非常多的优化策略来生成一个最优的执行计划:

  • 重新定义表的关联顺序(多张表关联查询时,并不一定按照SQL中指定的顺序进行,但有一些技巧可以指定关联顺序)

  • 优化MIN()和MAX()函数(找某列的最小值,如果该列有索引,只需要查找B+Tree索引最左端,反之则可以找到最大值,具体原理见下文)

  • 提前终止查询(比如:使用Limit时,查找到满足数量的结果集后会立即终止查询)

  • 优化排序(在老版本MySQL会使用两次传输排序,即先读取行指针和需要排序的字段在内存中对其排序,然后再根据排序结果去读取数据行,而新版本采用的是单次传输排序,也就是一次读取所有的数据行,然后根据给定的列排序。对于I/O密集型应用,效率会高很多)


执行器: 

    在分析器知道语句要干什么,优化器知道怎么做以后,下面就到了执行的阶段,执行是交给执行器的。执行器在执行的时候首先判断该用户对该表有没有执行权限,如果没有则会返回denied之类的错误提示。如果有权限,则会打开表继续执行。打开表的时候,执行器会根据表定义的引擎,去使用该引擎的接口。

比如 mysql> select * from T where ID=10; 例子中的表 T ,ID 字段没有索引,那么执行器的执行流程是这样的:

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

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

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

至此,这个语句就执行完成了。

    对于有索引的表,执行的逻辑也差不多。第一次调用的是“取满足条件的第一行”这个接口,之后循环取“满足条件的下一行”这个接口,这些接口都是引擎中已经定义好的。你会在数据库的慢查询日志中看到一个 rows_examined 的字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加的。在有些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟rows_examined 并不是完全相同的。


MySQL得到sql语句后,大概流程如下:

  • 0.连接器负责和客户端进行通信

  • 1.查询缓存:首先查询缓存看是否存在k-v缓存

  • 2.解析器:负责解析和转发sql

  • 3.预处理器:对解析后的sql树进行验证

  • 4.优化器:得到一个执行计划

  • 5.查询执行引擎:执行器执行语句得到数据结果集

  • 6.将数据放回给调用端。



二, 日志系统


     MySQL中有六种日志文件,分别是:重做日志(redo log)、回滚日志(undo log)、二进制日志(binlog)、错误日志(errorlog)、慢查询日志(slow query log)、一般查询日志(general log),中继日志(relay log)。


重做日志(redo log):

    是InnoDB引擎层的日志文件, 以物理的形式存储日志文件, 记录的是物理数据页面的修改的信息,其redo log是顺序写入redo log file的物理文件中去的。 事务开始之后就产生redo log,redo log的落盘并不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入redo log文件中。 当对应事务的脏页写入到磁盘之后,redo log的使命也就完成了,重做日志占用的空间就可以重用(被覆盖)。其作用是 确保事务的持久性。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。下图是一些redo_log的参数:

2, sql的执行流程和mysql日志系统


二进制日志(binlog)

     逻辑格式的日志,可以简单认为就是执行过的事务中的sql语句。 事务提交的时候,一次性将事务中的sql语句(一个事物可能对应多个sql语句)按照一定的格式记录到binlog中。其和用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。 用于数据库的基于时间点的还原。

二进制日志的作用之一是还原数据库的,这与redo log很类似,  但是两者有本质的不同:

    1,作用不同:redo log是保证事务的持久性的,是事务层面的,binlog作为还原的功能,是数据库层面的(当然也可以精确到事务层面的),虽然都有还原的意思,但是其保护数据的层次是不一样的。

    2,内容不同:redo log是物理日志,是数据页面的修改之后的物理记录,binlog是逻辑日志,可以简单认为记录的就是sql语句

    3,另外,两者日志产生的时间,可以释放的时间,在可释放的情况下清理机制,都是完全不同的。

    4,恢复数据时候的效率,基于物理日志的redo log恢复数据的效率要高于语句逻辑日志的binlog

关于事务提交时,redo log和binlog的写入顺序,为了保证主从复制时候的主从一致(当然也包括使用binlog进行基于时间点还原的情况),是要严格一致的,MySQL通过两阶段提交过程来完成事务的一致性的,也即redo log和binlog的一致性的,理论上是先写redo log,再写binlog,两个日志都提交成功(刷入磁盘),事务才算真正的完成。

    以下是binlog的一些配置参数:

    2, sql的执行流程和mysql日志系统


回滚日志(undo log):

      undo日志用于存放数据修改被修改前的值,假设修改 tba 表中 id=2的行数据,把Name='B' 修改为Name = 'B2' ,那么undo日志就会用来存放Name='B'的记录,如果这个修改出现异常,可以使用undo日志来实现回滚操作,保证事务的一致性。 事务开始之前,将当前是的版本生成undo log,undo 也会产生 redo 来保证undo log的可靠性,  当事务提交之后,undo log并不能立马被删除,而是放入待清理的链表,由purge线程判断是否由其他事务在使用undo段中表的上一个事务之前的版本信息,决定是否可以清理undo log的日志空间。 MySQL5.6之前,undo表空间位于共享表空间的回滚段中,共享表空间的默认的名称是ibdata,位于数据文件目录中。 MySQL5.6之前,undo表空间位于共享表空间的回滚段中,共享表空间的默认的名称是ibdata,位于数据文件目录中。其 保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读

    下图是其一些配置参数, 可以看到其也是InnoDB引擎层的日志文件:

2, sql的执行流程和mysql日志系统


ps: 公众平台更新了->2, sql的执行流程和mysql日志系统2, sql的执行流程和mysql日志系统2, sql的执行流程和mysql日志系统2, sql的执行流程和mysql日志系统

以上是关于2, sql的执行流程和mysql日志系统的主要内容,如果未能解决你的问题,请参考以下文章

Mysql 逻辑架构图及日志系统

MySQL | 日志系统:一条SQL更新语句是如何执行的?

讲日志系统:一条SQL更新语句是如何执行的

日志系统:一条SQL更新语句是如何执行的

日志系统:一条SQL更新语句是如何执行的

MySQL - 实战 - 基础架构和日志系统