查询语句的执行过程
上图就是一条查询sql所需要经历的过程;也差不多是mySql的结构
MySQL可以分为Server层和存储引擎层两部分。
Server层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖MySQL的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
而存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持InnoDB、MyISAM、Memory等多个存储引擎。现在最常用的存储引擎是InnoDB,它从MySQL 5.5.5版本开始成为了默认存储引擎。
连接器
在我们对数据库操作之前,第一步都是建立连接,会先连接到这个数据库上,这时候接待你的就是连接器。连接器负责跟客户端建立连接、获取权限、维持和管理连接;
在我们连接后,如果没有后续操作的话,那么这个连接就会处于空闲操作,长时间空闲的话,连接器就会将其断开,毕竟一个服务器的线程是有限的;长时间占用是比较浪费资源的,连接器默认断开的时候是 8小时;
建立连接的过程通常是比较复杂的,所以一般我们项目操作数据库的时候,都是使用的线程池,在使用的时候就连接,不使用时候返回线程池中,这样比直接连接断开好点,但是每次连接的成本还是比较大的,所以建议操作数据库的时候,尽量减少对数据库操作,能一次性查询就一次性查询,将压力转移给内存;
缓存
在完成连接后,我们就可以执行selec请求了
MySQL拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。之前执行过的语句及其结果可能会以key-value对的形式,被直接缓存在内存中。key是查询的语句,value是查询的结果。如果你的查询能够直接在这个缓存中找到key,那么这个value就会被直接返回给客户端。
如果语句不在查询缓存中,就会继续后面的执行阶段。执行完成后,执行结果会被存入查询缓存中。你可以看到,如果查询命中缓存,MySQL不需要执行后面的复杂操作,就可以直接返回结果,这个效率会很高。
查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。因此很可能你费劲地把结果存起来,还没使用呢,就被一个更新全清空了。对于更新压力大的数据库来说,查询缓存的命中率会非常低。除非你的业务就是有一张静态表,很长时间才会更新一次。比如,一个系统配置表,那这张表上的查询才适合使用查询缓存。
注:MySQL 8.0版本直接将查询缓存的整块功能删掉了,也就是说8.0开始彻底没有这个功能了。
分析器
如果缓存中没有的话,就要开始真正执行语句了。首先就轮到分析器了,分析器会分析这个查询语句的语法问题,比如语句少写或者用错关键词等;都是分析器这里分析出来的;
一般提示“You have an error in your SQL syntax”就是分析器这里出错了;
优化器
优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。
比如你执行下面这样的语句,这个语句是执行两个表的 join:mysql> select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;
既可以先从表 t1 里面取出 c=10 的记录的 ID 值,再根据 ID 值关联到表 t2,再判断 t2 里面 d 的值是否等于 20。
也可以先从表 t2 里面取出 d=20 的记录的 ID 值,再根据 ID 值关联到 t1,再判断 t1 里面 c 的值是否等于 10。
这两种执行方法的逻辑结果是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。
一般我们语句遇到错误是 “Unknown column ‘k’ in ‘where clause’” 一般是优化器阶段报错的;优化器会进行优化分析,比如用先执行哪个条件,使用哪个索引。如果没有对应的字段就会报错的
执行器
MySql通过分析器知道了你要做什么,通过优化器知道了改怎么做,于是就进入执行器,开始执行语句
不过执行器最先一步不是执行语句,而是对你当前的角色进行验证,看你有没有操作这个数据表的权限,如果没有直接报错
如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。
一般对于一个没有索引的表,比如id不是索引,查询id为10的一行
-
调用InnoDB引擎接口取这个表的第一行,判断ID值是不是10,如果不是则跳过,如果是则将这行存在结果集中;
-
调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。
-
执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。
对于有索引的表,执行的逻辑也差不多。第一次调用的是“取满足条件的第一行”这个接口,之后循环取“满足条件的下一行”这个接口,这些接口都是引擎中已经定义好的。
你会在数据库的慢查询日志中看到一个rows_examined的字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加的。
在有些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟rows_examined并不是完全相同的
存储引擎
mysql的存储引擎还是比较多的,但是目前5.5以后常用的就两种了InnoDB和MyISAM
InnoDB
MySQL5.5之后的默认存储引擎
应用场景:如果应用对事务的完整性有较高的要求,在并发条件下要求数据的一致性,数据操作中包含读、插入、删除、更新,那InnoDB是最好的选择。在计费系统、财务系统等对数据的准确性要求较高的系统中被广泛应用。
优点:提供了具有提交(Commit)、回滚(Rollback)、崩溃恢复能力的事务安全,支持外键。
缺点:相比较于MyISAM,写的处理效率差一点,并且会占用更多的磁盘空间来存储数据和索引
特点:
1、自动增长列
innoDB表的自动增长列必须是索引,如果是组合索引,也必须是组合索引的第一列
MyISAM表的自动增长列可以是组合索引的其他列
设置自动增长列:create表时,在字段后加auto_increment
可以通过alter table emp auto_increment=n 来强制设置自动增长列的初始值,默认是1,但是该强制指定的值是保存在内存中的,所以在数据库重启后会失效,需要重新设置
2、外键约束
MySQL的存储引擎中只有innoDB支持外键约束
注意:当某个表被其它表创建了外键参照,那么该表对应的索引和主键禁止被删除
当导入多个表的数据时,如果要忽略表之前导入顺序,或者当执行load data和alter table操作,为了提高处理速度的时候,可以暂时关闭外键约束,命令是
mysql> set foreign_key_checks=0;
执行完之后,再使其为1 ,开启外键。
查看外键信息
show create table 或show table status
3、存储方式
innoDB存储数据和索引有共享表空间存储和独占表空间存储两种方式,通过参数innodb_file_per_table控制,0表示共享空间,也是默认的,1表示独占空间
两种方式的表结构(描述)都保存在.frm文件中
共享表空间:
每一个数据库的所有表的数据、索引都保存在一个文件中,默认在data目录下,名为ibdata1,大小为10M的文件,可以通过参数innodn_data_file_path=/data/ibdata1:2000M来指定存储路径。
优点:
(1)、可以将表空间分为多个文件放在不同的磁盘上,分布IO,提高性能。innodn_data_file_path=/data/ibdata1:2000M;/db/ibdata2:2000M:autoextend
autoextend表示如果指定的2000M空间用满后,该文件自动增长。
也就是说采用共享空间存储,存储空间的大小不受文件系统下文件大小的限制了,而取决于自身的限制,官方文档显示,表空间的最大限制是64TB。
(2)、表数据和表结构放在一起,方便管理
缺点:由于所有的数据和索引都是在一个文件中混合存储,这样的话对一个表做了大量的删除操作后,表空间中会产生大量的空隙
独占表空间存储:
每一张表都有自己独立的表空间,表的结构依然在.frm文件中,还有一个后缀为.ibd的文件,保存了这张表的数据和索引。
优点:
每张表都有自己独立的表空间,可实现单表在不同数据库中移动
空间可回收。drop table会自动回收;删除数据后,通过alter table emp engine=innodb也可回收不用的表空间
效率和性能会好一些
缺点:由于每个表的数据都是以一个单独的文件来存放,所以会受到文件系统的大小限制
MyISAM
它是MySQL5.5之前的默认存储引擎
优势:访问速度快
适用场景:对事务的完整性没有要求,或以select、insert为主的应用基本都可以选用MYISAM。在Web、数据仓库中应用广泛。
特点:
1、不支持事务、外键
2、每个myisam在磁盘上存储为3个文件,文件名和表名相同,扩展名分别是
.frm -------存储表定义
.MYD --------MYData,存储数据
.MYI --------MYIndex,存储索引
数据文件和索引文件可以放在不同的目录,平均分布IO,加快访问速度,在创建表的时候通过 data directory和index directory来指定存储路径
3、myisam表还支持三种不同的存储格式
(1)、静态表(fixed)
默认的存储格式
静态表中的字段都是非变长字段,每个记录都是固定的长度,当表不包含变量长度列(VARCHAR, BLOB, 或TEXT)时,使用这个格式。
优点:存储迅速,出现故障容易恢复
缺点:占用空间比动态表大,静态表在进行数据存储时会按照事先定义的列宽度补足空格,但在访问的时候会去掉这些空格
注意:如果数据本身带有空格,在返回的时候会去掉数据本身自带的末尾的空格,前面的会保留
(2)、动态表(dynamic)
包含变长字段,例如varchar、、text、blob,如果一个MyISAM表包含任何可变长度的字段(varchar、blob、text),或者该表创建时用row_format=dynamic指定,则该表使用动态格式存储
优点:占用空间小
缺点:频繁的更新和删除操作会产生碎片,需要定期用optimize table语句或myisamchk -r命令来改善性能,并且在出现故障后较难恢复
(3)、压缩表
由myisampack工具创建,占据非常小的磁盘空间,因为每个记录都是被单独压缩的