一条mysql语句是如何执行的

本文详细介绍了MySQL的架构,包括server层和存储引擎层的功能组件。解释了连接器、查询缓存、分析器、优化器和执行器的工作原理。同时,深入探讨了InnoDB存储引擎的特性及redolog和binlog两种日志机制的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        MYSQL可以分成server层和存储引擎层两部分,server层包括连接器、查询缓存、分析器、优化器、执行器,他包含了大多数的核心服务,还有一些内置的函数,如时间,算数,加密等。储存引擎层负责数据的存储和提取,他支持InnoDB、MyISAM、Memeory等多个储存引擎,现在最常用的是InnoDB,当前是Mysql的默认的引擎。

下面介绍一下各个组件的作用。

连接器

        用来跟客户端进行连接的,他建立连接、权限认证、保持心跳等。连接是有最长时间限制的,wait_timeout,默认是8小时。连接是在MySql内存中保持的,断开时才会释放,所以为了防止内存溢出,一般要定期断开长连接,或者在执行完一个占用内存的大查询后,断开再重连,如使用mysql_reset_connection初始化连接资源,这样就不用重新认证。

缓存查询

有一条语句后,mysql会先查一下缓存,之前查询过的语句会以key-value的形式放在缓存中。缓存如果有对一个表的更新,那么这个表上的所有缓存都被清空,如果语句中,更新的操作比较多,那么缓存机制会加大数据库的压力。

分析器

对SQL语句进行词法分析,解析语句,校验语法规则,如果有语法错误就报出。

优化器

例如一场景,在表里面有多个索引,优化器需要决定用哪个索引,或者在一个语句有多表关联的时候,决定表的连接顺序,如select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20,可以先从t1中取c=10的记录,由它的ID关联到t2,也可以反过来先取t2的值,优化器会决定用哪个。

执行器

先检测有没有执行此操作的权限,之后就打开表正式执行这条语句,如有语句select * from Table where ID=10,

        1. 调用InnoDB引擎的接口拿到第一行,判断它的ID是不是10,是的话放在结果集中。

        2. 调用InnoDB引擎的接口取下一行,继续判断。

        3. 返回最终结果集。

Mysql中有一个字段是rows_examined,他表示在语句执行的过程中扫描了多少行。

以上就是一条查询语句的执行过程。


下面介绍更新语句的执行过程,在之前先看看Mysql有两个重要的日志模块,redo log(重做日志)和binlog(归档日志)。

redo log

        当有一条记录需要更新的时候,InnoDB会把记录写到redo log中,并且更新内存,那么这个更新就完成了,等到系统空闲的时候或者写满了redo log 的时候,就会写到磁盘中。一般redo log是固定大小的的一个循环的空间。

就算InnoDB发生了重启,redo log的数据也不会丢失。innodb_flush_log_at_trx_commit这个参数设置成1的时候,表示每次事务的redo log都直接持久化到磁盘。建议设置成1,这样可以保证MySQL异常重启之后数据不丢失。

binlog

        binlog是server层的日志。用于记录数据库执行的写入性操作(不包括查询)信息,以二进制的形式保存在磁盘中。 binlog 是 mysql的逻辑日志,并且由 Server 层进行记录,使用任何存储引擎的 mysql 数据库都会记录 binlog 日志。逻辑日志可以简单理解为记录的就是sql语句 。

介绍一下二者的区别,

  1. redo log是InnoDB引擎特有的,binlog是MySQL的Server层实现的,所有引擎都可以使用。
  2. redo是物理日志,记录了哪条数据的修改,binlog是逻辑日志,记录了语句的逻辑,如把某个数据的值加1。
  3. redo是循环写的,空间固定,满了之后会刷新磁盘。Binlog是追加写的,binlog一个文件满了之后,就会写到下一个,不会覆盖。

        同理,在binlog中innodb_flush_log_at_trx_commit这个参数设置成1的时候,表示每次事务的binlog都持久化到磁盘。建议设置成1,这样可以保证MySQL异常重启之后binlog不丢失。

下面看看update语句是怎么执行的

一条更新的语句如下:update T set c=c+1 where ID=2;

  1. 执行器找到引擎取到ID=2这一行,如果本来就在内存中,就返回给执行器,否则就从磁盘中读取。
  2. 执行器把这个值加上1,调用引擎接口写入这行新数据。
  3. 引擎把行数据更新到内存中,然后更新到redo log中,更新完之后告知执行器执行完了,可以提交事务了。
  4. 执行器生成binlog,写入日志。
  5. 执行器调用引擎的接口提交事务,引擎把redo log改成commit状态,更新完成。

两阶段提交

为了保证两个状态一致。

  1. 如果先写redo log后写binlog。那么redo log写完,还没有写binlog的时候,系统奔溃了,redo log在系统崩溃后还能恢复,此时c的值是1。但是binlog没写完,那么binlog里面没有这个语句,如果这时执行了binlog的数据恢复,因为binlog是没有这条操作记录的,这样恢复出来这一行的值就是0。
  2. 如果先写binlog再写redo log。Binlog写完后系统奔溃了还没有写redo,奔溃之后这个事务就无效了,但是binlog里面已经有了这条记录,那么在恢复的时候,就会多出了这条不应该成功的操作。

redo log和binlog都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值