MySQL 查询语句执行过程
Mysql分为server层
和存储引擎
两部分,或许可以再加一层连接层
连接层(器)
Mysql使用的是典型的C/S架构。连接器通过典型的TCP握手完成连接。
需要注的是,
如果用户名和密码都正确,那么该连接所拥有的权限仅仅是连接成功建立时的所读取到的权限
这就意味着:当连接已经建立后,我们在对该用户的权限进行修改,这些修改要直到该用户再次建立连接时才会生效。
这听起来是个不好的设计,因为一旦建立连接,管理员是无法临时收回权限的。
索性,MySQL也想到了这一点,因此对于已经连接的空闲连接,在一定时间后会自动断开 --- 由参数wait_timeout
控制,默认值是8小时。
我们可以使用
show processlist
查看已有连接是否处于空闲(Sleep)状态
想要使用示例数据库详见此处
我想,应该是为了用户权限的“稳定”才有了上面所谓的“不安全”的设计,因此使用DCL语句的时候要更加谨慎才行。
另外需要注意的是,
MySQL在执行过程中临时使用的内存是管理在连接对象中的
这就意味着,当我们连接一次然后不断通过该连接进行操作时(即使用长连接时),临时内存会不断积累,直到连接断开的时候才释放。但当内存占用过大,被系统杀掉(OOM --- Out of memory ),就会表现为MySQL异常关闭/重启。
为了避免这种状况我们可以使用两种规避方式:
- 避免长连接,尽量使用短连接 --- 但建立连接其实是很耗时的
- 使用MySQL5.7或者更高版本,可以通过
mysql_reset_connection
来初始化连接 --- 即在不重建连接的情况下释放临时内存(它是一个API方法,而不是直接在mysql shell中使用的命令,详见)
server层
就根据各个层次的名字一样,顾名思义,我们主要在在server层处理一条SQL语句,而这个过程在MySQL8.0版本后如下所示:
(连接器)>> 分析器 >> 优化器 >> 执行器
-
分析器就是对SQL字符串的拆分与辨析
-
优化器就是“择优”,即
在表里有多个索引的时候选择使用哪个索引、在多表关联(join)的时候选择速度最快的join方式,如在进行如下查询时
select * from t1 join t2 using(Id) where t1.a=10 and t2.b=20;
优化器就会帮助我们选择是 “先选出t1.a=10的部分再关联t2” 还是 “先选出t2.b=20的部分再关联t1”
-
执行器,
开始执行 》 判断有没有相关权限 》使用表定义中的引擎 》 进行扫描执行语句
在8.0之前的版本还有“查询缓存”的机制,就是将查询过的结果放在缓存中以期望下次再次执行相同查询时能快速返回结果。但...哪里有那么多相同的查询呢,更过分的是这里的相同还要求表要没有发生改变,且语句的大小写都要相同。Are you serious ?于是弃之。
存储引擎
MySQL存储引擎负责存储和提取,其架构是插件式,支持(默认)InnoDB等多个存储引擎。
搜索引擎是针对表的,在create table 时可以使用engine = xxx来使用指定内存引擎。
让MySQL为我们记录执行流程