首先,先要来了解一下mysql里面都有哪些“零件”,我们把拆分开来,让你对mysql有更深入的理解。这样我们在碰到mysql的一些异常或问题,可以有个思想概念知道问题发生在哪一阶段,该如何解决。
mysql大体来说分为两层:
- Server
- 存储引擎
1.Server:
- 连接器
- 查询缓存
- 分析器
- 优化器
- 执行器 (核心服务功能、内置各种函数、存储过程、触发器、视图)
2.存储引擎(plugin架构模式):
- MyISAM
- Memory
- InnoDB(mysql5.5.5成为默认存储引擎)
下面让我们来分别介绍一下他们两大层的“零件”主要用途:
连接器
执行逻辑第一步:与数据库进行一个连接握手操作,交于连接器负责。它主要负责与客户端建立连接、获取权限、维持和管理连接。
注:当与服务端建立连接后,完成身份认证与权限获取后,若再用管理员的账号对此账号进行权限修改是不会影响已存在的连接。换而言之,修改完后生效期在该账号下次与服务端重新建立连接时。
在连接长时间不产生动作,连接器会自动断开,这个时间周期为wait_time=28800,即8小时。
注:若客户持续的进行请求,推荐建立长连接进行处理。而不是短连接:每次执行很少的几次查询边断开,下次再重新建立。因为在建立连接的过程是比较复杂的。
当我们再与mysql建立长连接时,有时mysql的内存涨的很快,这是因为在执行过程中使用的内存是管理在连接对象中的。这些资源并不会在用完就回收,而是在你断开连接后才会释放掉,所以才会导致内存占用越来越大而出现崩盘。
注:解决思路如下:
1.定期断开连接
2.执行mysql_reset_connection初始化连接状态:此过程不是重新建立连接,也就是不会重新连接与重新做权限验证,而是把连接恢复到刚刚连接创建完的一种状态(mysql5.7之后可用)
连接情况可用 show processlist 查询出结果
查询缓存
执行逻辑第二步:查询缓存。
注:以key-value的方式存储
key:执行的select语句
value:查询的结果集
当你输入一个select语句时。首先会到查询缓存看看是否之前已查询过,看是否能找到相对应的值。
1.若key存在,则直接返回对应结果集
2.若不存在则会进入下一阶段继续执行。当查询到结果集时会被存入缓存中。
注:1.这时我们便想,之后一直查询缓存中的数据效率会很高,但是这是针对应用场景的,比如频繁的查询的表可以加上,频繁的更新表则不必加上。
2.因为当表进行了update操作则会清除该表的所有查询缓存
3.mysql8.0已将查询缓存功能删除,既然官方都觉得这种方式不可取,那当然是不建议用咯
分析器
执行逻辑第三步:此时开始做执行sql的预前工作。
首先,mysql内建解析器,对语法进行检查。
检查顺序为:from->on->join->where … >生成新的解析树->语义检查(例如没有该列)等 ;
注:mysql在此阶段不仅仅会判断语句是否正确,也会判断表是否存在,列是否存在。
优化器
执行逻辑第四部:在分析器处理完成后,其实mysql已经知道你需要向那拿数据了,但是怎么去取,效率如何便需要优化器在进行一次处理。
当表中有许多索引时,比如列A与列B都建立了所有。当一条sql查询时要都需要这两个列作为查询条件:
select * from table where A=1 and B=2
这个时候,我们是否可以做出两个选择:
选择A:我先取出列A=1的数据,然后再比较列B的数据是否为2
选择B:我先取出列B=2的数据,然后再比较列A的数据是否为1
虽然最终的目的是一样的。但是在过程中,我们比较的次数是不同的,也就是执行的效率是不同的。
而优化器的工作便是帮我们效率最高的执行方式。
执行器
执行逻辑第五步:此时才是真正开始执行sql语句。
在开始执行时,会进行一个权限验证,来判断你是否拥有操作这张表的权限。如果没有则会返回错误。若有,则会根据该表的引擎定义去查询。
执行流程:
1.调用InnoDB引擎取该表第一行数据进行条件判断,满足则存入结果集。
2.继续调用引擎取“下一行”,直到取完为止。
3.返回所有满足条件的行组成的结果集给客户端。
小结
为什么执行器中还有对权限验证的操作,为什么不可以放入分析器之后做处理?
1.sql在执行过程中可能会有触发器这种在运行时才能确定的过程。分析器结束后的precheck是无法对这种运行时涉及到的表进行权限验证的,所以需要在执行器中检查。
2.正因为有precheck这个步骤,若用户对该表无权限会报无权限的错误,而不是列不存在(减少暴露表结构)。
3.词法分析阶段是从information schema获取表结构信息。