《MySQL实战45讲》学习笔记——SQL语句的执行

MySQL 逻辑架构(图片来自MySQL实战45讲文稿):
《MySQL实战45讲》学习笔记——SQL语句的执行_第1张图片
MySQL 的存储引擎是插件式的,这个系列讲座主要讲的是InnoDB存储引擎。

连接器:管理连接,权限验证。

MySQL有一个管理数据库mysql,mysql数据库中有一个表叫做user,user表中保存了4部分内容:用户,权限,安全和资源控制。用户部分保存了用户名和密码以及允许连接的Host。权限部分规定了用户是否可以查询,删除数据,更改权限,关闭服务器等。安全部分是和数据加密相关的。资源控制部分规定了用户使用服务的能力,如每小时允许的操作次数。

mysql数据库中,还有一个db表,db表中保存了用户对于某个数据库的操作权限,权限项的内容和user表差不多。

mysql数据库中的host表规定了访问主机的权限。

在MySQL 8.x 上好像已经没有host表了。上述文档是MySQL 5.7版本的。

还有一点要注意,一个用户成功连接后,管理员再更改账号权限是不会影响到已连接用户的。

可以用show processlist命令查看所有连接。处于空闲(sleep)状态的连接超过一定时间会被自动断开,这个由参数wait_timeout控制,默认是8小时。

MySQL有些资源是在断开连接的时候释放的,如果一直保存长连接,有时候内存使用会不断增长,在程序中可以考虑在适当的实际断开连接重建。这个时机一般是一个比较大的查询。

MySQL 5.7以后可以使用mysql_reset_connection来重新初始化连接资源

查询缓存

查询缓存会缓存执行过的查询语句,再次遇到同样的查询语句的时候可以直接返回结果。但是对表级别的更新操作会让查询缓存失效,返回造成资源浪费,所以如果插入是一个比较常规的操作,建议关闭查询缓存,只有几乎静态的数据表查询适用查询缓存。

MySQL 8.0开始已经不支持查询缓存了

分析器

分析器就是解析SQL语句,如果SQL语句有错误,分析器会给出错误提示。

优化器

优化器决定使用哪个索引,决定表的连接顺序等。总之,优化器会定下查询方案。

执行器

如果有索引,拿到索引结果;如果没有索引,扫描全表。总的逻辑是,拿到满足条件的第一行,然后循环取满足条件的下一行。

讲座中给出的是只有一个查询条件的例子,对于有多个查询条件,我觉得应该是最外边的循环是查询条件,内部的循环是满足当前条件的行读取循环。而不是逐行扫描是否满足所有条件。

更新语句的执行

更新语句和查询语句的执行流程的主要区别是,更新语句涉及日志系统。

日志系统有两个:重做日志(redo log)和归档日志(binlog)。binlog是MySQL日志自带的log,是Server层实现的日志系统,和数据库备份一起恢复数据用。redo log是InnoDB存储引擎的log,用于保证crash-safe。

为什么InnoDB要实现自己的日志系统呢?为了了解这个问题,先要了解InnoDB存储引擎的二段提交过程。比如一个更新语句:

mysql> update T set c=c+1 where ID2;

InnoDB执行update的流程;

  1. 执行器先找引擎取ID=2这一行。ID是主键,引擎直接使用树搜索到这一行,如果ID=2这一行在内存中,直接返回,否则需要从磁盘读取到内存,再返回给执行器。
  2. 执行器拿到这行数据,把这个值+1,得到新的一行数据,在调用引擎接口写入这行数据。
  3. 引擎将这行新数据更新到内存中,同时记录这个更新操作到redo log里,此时redo log处于prepare状态。然后告知执行器执行完成。
  4. 执行器生成这个操作的binlog,并把binlog写入磁盘。
  5. 执行器调用引擎提交事务的接口,引擎把刚刚写入的redo log状态改为commit,更新完成。

数据更新如果每次都以事务的方式写入磁盘,则IO开销太大。所以一般是先写入内存,然后在空闲的时候集中写到磁盘,但是此时如果MySQL Crash,则会丢失内存中的数据。InnoDB采用的这种技术叫做WAL(Write-Ahead Logging),就是将相对简单的日志写入磁盘,数据仍保存在内存中,如果Crash,可以根据日志将未保存的数据恢复。这就是redo log的作用。

redo log和binlog的不同之处:

  • redo log是InnoDB引擎特有的;binlog是MySQL Server 层实现的。
  • redo log是物理日志,记录的是“在某个数据页面上做了什么修改”;binlog是逻辑日志,记录的是这个语句的原始逻辑。比如“给ID=2这一行的c字段增加1”
  • rego log 是循环写的,空间固定,用完循环;binlog是追加的,文件写到一定大小后会切换到下一个。

innodb_flush_log_at_trx_commit这个参数是提交的时候将redo log持久化到磁盘的频率,建议设置成1

sync_binlog这个参数是提交的时候binlog持久化的频率,也建议设置成1.

这两个参数都设置成1之后,数据就不会丢失了。

你可能感兴趣的:(后端)