上一篇文章讲述了Mysql的基本框架,和sql执行的流程,这篇文章首先分析下每个流程的具体细节,然后介绍日志文件和数据文件
截图 (2).png
以下面语句作为例子来分析流程中每一步的具体细节:
select * from t1 where id=10000;
连接器
mysql>mysql -uroot -p
连接器负责建立、管理、维护连接,获取权限,当输入上面的命令的时候会要求输入密码,账户密码校验通过之后就是建立连接,同时获取该账户的权限,也就是说当这时管理修改了该用户的权限的话,对于当前连接也是没有影响的。
查询缓存
当连接建立完成之后,会先到查询缓存中查看时候有缓存存在,select语句的hash值作为key,查询结果作为value,当key存在于缓存当中时,直接返回value,当key不存在时候会继续执行后面的流程,流程执行结束之后,将查询结果放入查询缓存中,值得注意的是查询缓存往往利大于弊,因为查询缓存失效太频繁,当表中有数据更新时,mysql就会清除查询缓存,所以不建议使用查询缓存,mysql8之后也将查询缓存功能删除了
分析器
当查询缓存中不存在key时流程进入到分析器中,分析器主要负责词法分析和语法分析,首先会做词法分析,输入的一条SQL语句是由多个字符串和空格组成的,MYSQL需要识别出字符串是什么,代表什么意思,如关键词select,识别出来这是一个查询语句,字符串t1识别为表名t1,id识别为例id。之后就是做语法分析,根据词法分析结果,语法分析器会根据语法规则,判断是你输入的这个SQL语句是否满足Mysql语法,如果语法不对,就会收到语法错误提醒
优化器
经过了分析器之后Mysql就知道你要做什么了,在开始执行之前Mysql还会经过优化器的处理,例如索引的选择,多表join的时候,选择那个表作为驱动表,例如下面的语句
mysql>select * from t1 join t2 on t1.code = t2.code where t1.a=10 and t2.a=10;
当执行这条语句的时候Mysql有两个选择:
- 先从t1表中取出a=10的记录,然后根据code关联到t2,再判断t2的a是否等于10
- 先从t2表中取出a=10的记录,然后根据code关联到t1,再判断t1的a是否等于10
很明显两种方法的执行结果是一样的,但是执行效率会有不同, 优化器要做的就是选择最优的方案
执行器
Mysql经过了优化器之后,就进入了执行器阶段,开始执行语句,执行之前会先判断是否有执行权限,如果没有则会报错,如果有权限,则会打开表继续执行,执行就会调用具体引擎的接口,比如我们这个例子中id字段没有索引,则执行器的执行流程如下:
调用InnoDB引起的接口取出表中的第一行,判断id是不是等于10,如果不是则跳过,如果是则将这行存在结果集中
调用引擎接口取下一行,重复相同的逻辑判断,知道渠道这个表的最后一行
执行器将上述遍历过程中所有满足条件的行组成记录集作为结果集返回给客户端
至此,这个语句就执行完成了
Mysql的物理结构
mysql是通过文件系统对数据和索引进行存储的
mysql从物理结构上可以分为日志文件和数据索引文件
日志文件
Mysql通过日志记录了数据库操作信息和错误信息,常用的日志文件有错误日志、二进制日志、查询日志、慢查询日志和事务Redo日志、中继日志等
可以通过命令查看当前数据库中的日志使用信息:
show VARIABLES like 'log_%';
错误日志(errorlog)
默认是开启的,Mysql5.5.7之后无法关闭错误日志,错误日志记录了运行过程中遇到的所有的严重错误信息以及Mysql每次启动和关闭的详细信息,
错误日志可以通过log-error和log-warnings来定义,其中log-err是定义是否启用错误日志的功能和错误日志的存储位置,log-warings是定义是否将警告信息也定义至错误日志中
log-error=/var/log/mysqld.log
#使用1|0来定义启动和关闭
log_waring=1
二进制日志
默认是关闭的,可以通过下面的配置开启
log-bin=mysql-bin
其中mysql-bin是binlong日志文件的basename,binlog日志文件的完整名称:mysql-bin-000001.log
binlog记录了数据库的所有的ddl语句和dml语句,但不包括select语句内容,语句以事件的形式保存,描述了数据的变更顺序,binlog还包括了每个更新语句的执行时间信息,如果是DDL,则直接记录到binlog日志,而DML语句必须通过失误提交才能记录到binlog日志中。
binlog主要用于实现mysql的主从复制、数据备份、数据恢复。
通用查询日志(general query log)
默认情况下是关闭的,由于通用查询日志会记录用户的所有操作,其中还包括增删改查等信息,在并发操作的大的环境下会产生大量的信息从而导致不必要的磁盘IO,会影响mysql的性能,如果不是为了调试数据库的目的建议生产环境不要开启查询日志
show global VARIABLES like 'general_Log';
开启方式如下:
#启动或关闭
general_log=(ON|OFF)
#日志文件变量,如果general_log_file没有指定,默认名是host_name.log
general_log_file=/path/to/file
#记录类型 table:将日志存入数据库,file:将日志存入文件
log_output=(TABLE|FILE|NONE)
慢查询日志(show query log)
默认是关闭的,可以通过如下设置进行开启:
#开启慢查询日志
slow_query_log=ON
#慢查询的阈值
long_query_time=1
#日志文件如果没有给出file_name,默认为主机名,后缀为-slow.log,如果给出了文件名,但不是绝对路径、文件则写入数据目录
slow_query_log_file=file_name
记录执行时间超过long_query_time秒的所有查询,便于收集查询时间比较长的SQL语句
重做日志(redo log)
作用:确保事务的持久性。防止在发生故障的时间点,尚有葬爷未写入磁盘,在重启myslq服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性
内容:物理格式的日志,记录的是物理数据页面的修改的信息,其中redo log是顺序写入redo log file的物理文件中的。
什么时候产生:事务开启之后就会产生redo log,redo log的落盘并不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入redo log文件中
什么时候释放:当对应的事务的脏页写入到磁盘之后,redo log的使命也就是完成了,重做日志占用的空间就可以重用(被覆盖)
对应的物理文件:默认情况下,对应的物理文件位于数据库的data目录下的ib_logfile1&ib_logfile2,innodb_log_group_home_dir指定日志文件组所在的路径,默认是/,表示数据库的数据目录下。innodb_log_files_in_group指定重做日志文件组中的文件的数量,innodb_log_file_size指定重做日志文件的大小
其他:很重要的一点,redo log是什么时候写盘的?前面说了是在事务开始之后逐步写盘的,之所以说重做日志是在事务开始之后逐步写入,而不一定是事务提交才写入,原因就是重做日志有一个缓存区innodb_log_buffer,默认大小为8M,innodb存储引擎先将重做日志写入innodb_log_buffer中。然后通过三种方式将innodb日志缓冲区的日志刷新到磁盘 1、每秒一次执行刷新innodb_log_buffer到重做日志文件。2、每个事务提交时会将重做日志刷新到重做日志文件。3、当重做日志缓存可用空间少于一半是,重做日志缓存被刷新到重做日志文件
回滚日志(undo log)
作用:保存了事务发生之前的一个数据版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读(快照读)
内容:逻辑格式的日志,在执行undo的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,这一点是不同于redo log的
什么时候产生:事务开始之前,将当前的版本生成undo log,undo也会产生redo来保证undo log的可靠性
什么时候释放:当事务提交之后,undo log并不能立马被删除,而是放入待清理的链表,有purge线程判断是否由其他事务在使用undo段中的表上一个事务之前的版本信息。决定是否可以清理undo log的日志空间
对应的物理文件:Mysql5.6之前,undo表空间位于共享表空间的回滚段中,共享表空间的默认名称是ibdata,位于数据文件目录中,Mysql5.6之后,undo表空间可以配置成独立的文件,但是提前需要在配置文件中配置,
中继日志(relay log)
是在主从复制环境中产生的日志
主要作用是为了丛机可以从中继日志中获取到主机同步过来的SQL语句,然后执行到从机中。
数据文件
数据文件写入是随机IO
InnoDB数据文件
.frm文件:主要存放与表相关的数据信息,主要包括表结构的定义信息
.ibd:使用独享表空间存储数据和索引信息,一张表对应一个ibd文件
ibdata文件:使用共享表空间存储数据和索引信息,所有表共同使用一个或者多个ibdata文件
MyISAM数据文件
.frm文件:主要存放与表相关的数据信息,主要包括表结构的定义信息
.myd文件:主要用来存储表数据信息
.myi文件:主要用来存储表数据文件中任何索引的数据树
更多技术文章可关注个人公众号: 码农Fly
网友评论