Mysql结构及一条sql执行过程分析
1.Mysql结构
整个MySQL 由以下组成:
包括客户端、服务端server、存储引擎
1.1 客户端
navicat,mysql,jdbc,SQLyog等都属于客户端。
1.2 服务端
主要包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
1.2.1 连接器
上面说了mysql有很多的客户端,这些客户端要向mysql发起通信必须跟server端建立连接,这个工作就是连接器来完成的。
-- 可以通过这个命令查看sql的连接
show processlist
1.2.1.1 关于mysql的长连接短连接
1.长连接:是指一个连接建立后,后续客户端持续有请求都是用这个连接
2.短连接:每次执行完很少的几次查询就断开连接
开发中我们大多使用长连接,把长连接放在Pool内进行管理,但是长连接有些时候会导致MySQL占用内存涨的特别快,这是因为MySQL在执行过程中临时使用的内存是管理在长连接对象中的。这些资源会在长连接断开时 才释放,如果长连接积累下来,可能会导致内存占用过大,被系统强行杀掉(OOM),从现象看就是MySQL重启了。
以下是几种可能导致MySQL通过长连接临时占用过多内存的情况:
-
大量并发查询:当多个查询同时发生时,每个查询都可能分配一部分临时内存用于处理数据。如果查询量非常大,这些临时内存累积起来可能导致显著的内存占用。
-
复杂查询:复杂的查询,尤其是涉及大量JOIN操作、子查询或临时表的查询,通常需要更多的临时内存来存储中间结果和计算数据。
-
大数据集处理:处理大量数据时,MySQL可能需要更多的内存来缓存和排序数据。例如,排序操作可能使用排序缓冲区来存储待排序的数据,如果数据量很大,这个缓冲区也会很大。
-
长时间运行的事务:长时间运行的事务可能会累积大量的临时表和查询缓存,这些都会占用内存。
-
连接数过多:虽然长连接有助于减少连接和断开连接的开销,但如果连接数过多,每个连接都可能占用一定的内存,累积起来可能导致内存占用过高。
怎么解决这类问题:
- 如果你用的是 MySQL 5.7 或更新版本,可以在每次执行一个比较大的操作后,通过执行 mysql_reset_connection 来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态。
1.2.2 查询缓存
MySQL 拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。之前执行过的语句及其结果可能会以 key-value 对的形式,被直接缓存在内存中。key 是查询的语句,value 是查询的结果。如果你的查询能够直接在这个缓存中找到 key,那么这个 value 就会被直接返回给客户端。
如果语句不在查询缓存中,就会继续后面的执行阶段。执行完成后,执行结果会被存入查询缓存中。你可以看到,如果查询命中缓存,MySQL 不需要执行后面的复杂操作,就可以直接返回结果,这个效率会很高。
大多数情况查询缓存就是个鸡肋,为什么呢?
因为查询缓存往往弊大于利。查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。因此很可能你费劲地把结果存起来,还没使用呢,就被一个更新全清空了。对于更新压力大的数据库来说,查询缓存的命中率会非常低。
一般建议大家在静态表里使用查询缓存,什么叫静态表呢?就是一般我们极少更新的表。比如,一个系统配置表、字典表,那这张表上的查询才适合使用查询缓存。好在 MySQL 也提供了这种“按需使用”的方式。你可以将my.cnf参数 query_cache_type 设置成 DEMAND。