如下图所示,从宏观角度来说MySQL架构可以分为server层和存储引擎层,其中Server层包含如下:
接下来说说存储引擎,对于MySQL而言存储引擎是支持插拔的,常见的存储引擎有myisam、innodb、memory,而MySQL默认的使用的是innodb。
对于MySQL而言,客户端和服务端之间采用的是一种半双工的通信协议,这样就意味着同一时刻要么客户端向服务端发送数据,要么服务端向客户端发送数据。这意味着客户端必须完整的收到服务端响应的数据才能断开连接。
这个交互流程也在告诉我们,进行大量数据查询的时候,若无必要尽可能使用limit进行分页查询,避免这种全双工的通信方式导致客户端接收导致资源长时间的占用。
主要判断用户登录的账户密码是否正确,如果账户密码都正确,则进行权限查询,注意在本次连接期间只要不断开,无论外界如何修改权限,这个会话的权限都是以连接器查询到的为主。
MySQL8已经废弃的功能,这个功能常用于结果的缓存复用以提高查询性能,例如我们进行select * from table where id=1的查询。第一次发现缓存中没有,就从数据库中查出来并放到缓存中下次可以在复用。
MySQL8之所以废弃是因为数据库中的数据经常更新导致缓存失效,就需要清空这个缓存,这期间和开销是非常没必要的,所以索性废掉这个功能。
分析器主要是负责sql解析和预处理,它会将客户端发来的查询一句进行解析生成一颗解析树,然后解析器根据自定义规则对sql语句进行词法和语法分析。
分析器分析无误之后,说明这条语句是可以正常执行的。MySQL优化器就会通过分析找出成本最小的一种方式生成执行计划,交由执行器执行。
对此,我们这里不妨补充一下MySQL能够自己处理的一些优化类型:
SELECT *
FROM table1
LEFT JOIN table2
ON table1.id = table2.id;
举个例子,上面的sql如果table1对应的id在table2中都有,那么sql语句就会变成这样
SELECT *
FROM table1
LEFT JOIN table2
ON table1.id = table2.id
WHERE table2.id IS NOT NULL;
然后优化器就会将其优化成这样
SELECT *
FROM table1
inner JOIN table2
ON table1.id = table2.id
WHERE table2.id IS NOT NULL;
使用代数等价变换规则,例如我们的查询条件是5=5 and a>5
,那么MySQL就会将其优化为:a>5
,再比如说我们有这样一条SQL,条件语句为(a<b and b=c) and a=5
,那么MySQL就会将其优化为: b > 5 and b=c
优化min、max,对于建立索引的数据表来说,使用索引所在列的进行最大值和最小值查询时,MySQL优化器会将这种sql判定为常数查询,例如笔者建立的下面这张表,我们将table1的id设置为索引。
然后查询下面这句sql:
SELECT min(id)
FROM table1;
使用explain查看其执行计划,可以看到执行计划显示Select tables optimized away,这就意味查询时它已经将表移除,而是用一个常数查询来代替。
select * from table1 where id=1+2
,MySQL优化器就会将其转为select * fromt table1 where id=3
。Select tables optimized away
那么执行计划就会显示Impossible WHERE从而提前终止查询:
对用户进行权限校验,若权限校验不通过则报错,然后执行器就会根据优化器优化后的执行计划(这里的执行计划是一个数据结构),执行器根据这个数据结构顺序调用存储引擎提供的API进行数据查询,并将查询结果返回给客户端,从而完成一次完整的SQL查询。
了解SQL执行过程之后,我们不妨通过一个实际的例子带入一下了解全过程。
sql如下所示:
select * from table where b=1 and a=2;
按照我们上文所说的过程:
联合索引(a,b)
,那么优化器就会遵循最左匹配原则将a,b
条件进行调换。更新语句我们示例SQL
如下:
update table set a=1 where b=1;
步骤还是一样:
(mysql8不走这一步)
API
,将这个修改写入内存中,同时记录redo log
,此时redo log
是prepare
状态,然后执行器执行操作,完成后提交事务成功,写入bin log
,最后redo log
更新为commit
。