查询语句执行
咱们首先来讲一下MySQL中一条查询sql的执行过程,希望通过这个过程说明可以很好的了解MySQL的运行机制。
大体的过程是:首先客户端发送一条查询语句到连接器,在连接器通过权限认证后查看查询缓存(query cache),如果这个查询在该缓存中则直接返回结果,但是如果不在该缓存中则到解析器,解析器通过语法解析和词法解析查看查询语句是否合法并将该查询语句解析成MySQL可以读懂的语言,然后通过优化器对该查询sql进行优化,选择最优的执行计划,最后通过执行器对sql执行。
连接器:是连接外部请求到MySQL的server端,并对其进行密码认证和权限认证。
查询缓存:一般会选择关闭,因为当对该表进行更新操作时,该表上的所有的查询缓存都会被清除。
解析器:对sql进行语法解析和词法解析,将对人友好的sql解析成对MySQL自己友好的语句。同时判断该sql的语法和词法是否正确,如果不正确则直接返回报错信息。
优化器:MySQL通过优化器确定最优的执行计划
执行器:真正的执行sql,并返回给客户端查询结果
更新语句执行
一条update更新操作的执行过程:
整体的执行过程和查询语句执行过程相同,但是执行器的执行执行完sql读取到数据之后的数据处理部分是什么样子呢,我们可以大概聊一下。现在以innodb存储引擎为例,因为从5.7之后的版本默认的存储引擎就是innodb存储引擎,并且8.0后的版本取消了myisam存储引擎。
MySQL将从磁盘上的数据缓存到内存中,然后执行器执行update操作并将源数据记录在undo中,之前的数据以视图的方式保留下来,直到没有事务再应用该数据后才会被释放,这就是MySQL的MVCC(多版本并发控制)。
查询语句和更新语句真正不同的是redo log和binlog的更新。当一条更新语句执行时MySQL会有日志先行的策略,首先是写redo,其中redo记录的时数据的物理信息,它是循环覆盖写的。当更新操作记录到redo中后会是prepare状态,然后是binlog进行记录然后提交最后redo进行commit,这个过程就是MySQL的两阶段提交。其中Binlog记录的是更新语句的逻辑信息,redo可以保证数据库的crash恢复。这时候咱们就有一个疑问了,如果我更新一条数据整好redo log写入磁盘了但是binlog还没有来得急提交,这时候服务器宕机,当再次重启服务器和数据库后这个事务怎么办呢?这时候MySQL为了数据的一致性,就会根据redo进行回滚操作从而保证数据的一致性。但是如果binlog也提交了但是redo还没有来得及提交,数据库启动后会认为这个事务以经完成了所以就会执行commit提交该事务。
说到这儿就不得不说一下控制redo和binlog的参数:
MySQL中有一个很有名的日志提交参数配置就是双1配置:
sync_binlog=1:binlog会在每次提交事务都会记录在磁盘中。当该值为0时则由操作系统自己判断当不繁忙再进行落盘,当为N则指有N个事务才进行落盘操作
innodb_flush_log_at_trx_commit:当该值为1时指事务提交及时刷新redolog到磁盘中保证了数据的安全,当为0时指的时redo每秒刷新一次,当为2时指的时有操作系统自己判断什么时候刷新。