MySQL Server层对象解读
-
一条查询语句从连接上MySQL服务器到返回数据这个过程在MySQL中还是有点复杂的
-
下面我们我们就以此为突破口,来了解哈MySQL的各个功能模块的执行过程
大致上来说:MySQL可以分为Server层和储存引擎层两部分
Server层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等
存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎
连接器
连接器负责跟客户端建立连接、获取权限、维持和管理连接
-
在完成经典的TCP握手后,
-
用户输入账户名和密码连接MySQL服务器,连接器开始认证你的身份
-
如果全部通过,则连接成功,此时可以通过一下命令查看连接信息
-
show processlist;
-
-
如果连接成功,但是我们长期没有任何动作,这个连接会处于空闲状态,比如上面的Sleep
-
默认8个小时无动作,自动断开连接
-
可在配置文件配置:wait_timeout
-
-
-
连接也分长连接和短连接
-
长连接:指连接成功后,如果客户端持续有请求,则一直使用同一个连接
-
短连接:则是指每次执行完很少的几次查询就断开连接,下次查询再重新建立一个
-
-
我们在使用MySQL的过程中,频繁的创建短连接不是很好,如果一直使用长连接也会导致MySQL占用的内存越来越大,直到OOM,被系统杀掉后重启,都不可取,以下解决手法可供参考
-
定期断开长连接。
-
使用一段时间,或者程序里面判断执行过一个占用内存的大查询后,断开连接,之后要查询再重连
-
-
如果你用的是 MySQL 5.7 或更新版本
-
可以在每次执行一个比较大的操作后,通过执行mysql_reset_connection 来重新初始化连接资源
-
这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态
-
查询缓存
建立连接之后,我们的sql语句就可以执行了,但在执行之前有一个拦路虎,那就是查询缓存
默认是关闭的,可通过该命令查看状态
show variables like 'query_cache_type';
也可以查询缓存的命中次数:
SHOW STATUS LIKE 'Qcache_hits'
如果是要开启缓存,可在配置文件my.cnf中配置如下
query_cache_type=1
在MySQL8.0版本中,这个查询缓存模块已经被移除
-
MySQL得到我们的sql语句,会对其进行hash,然后拿着hash结果去缓存中对比是否命中
-
如果命中,就说明之前执行过该sql,可以将缓存中的数据直接返回,一个sql到此结束
-
如果没有命中,才会继续走下去,直到拿到数据后,将数据缓存起来响应给客户端为止
-
在这个过程中,由于缓存的存在,会使查询加快很多,但是我不建议使用缓存,为什么?
-
首先说结果,使用缓存的结果是弊大于利
-
如果使用缓存,MySQL会多出一份精力来维护这份内存的中数据
-
缓存中的数据非常容易失效,随便更新一个表中的数据,该缓存就得失效
-
所以一般缓存的命中率非常的低,除非你的表示一个静态表,长时间不会更新
-
-
我们可以将参数 query_cache_type 设置成 DEMAND
-
对于默认的 SQL 语句都不使用查询缓存
-
而对于你确定要使用查询缓存的语句,可以用 sql_cache 显式指定,比如
-
select sql_cache * from user where user_id = 1;
-
-
分析器
MySQL得到用户的sql语句,就要先识别sql,于是来到了sql解析阶段
这个阶段就是 MySQL 的 Parser 解析器和 Preprocessor预处理器模块的功能
我们就以这个sql作为列子来说明如何解析的
select customer_id,first_name,last_name from customer where customer_id=14;
-
第一步sql分割,分割为10个字符串,识别关键字
-
select,customer_id,first_name,last_name,from,customer,where,customer_id,=,14
-
-
第二步语法分析( Parser 解析器)
-
语法分析器会根据语法规则做语法检查,判断你输入的这个SQL 语句是否满足 MySQL 语法
-
如果语法正确,就会更具MySQL定义的语法规则,生成一个解析树
-
-
第三步预处理器检测树是否合法(Preprocessor预处理器)
-
当语法解析器吧sql语句解析成树之后,预处理器会对这个树做合法检测
-
比如该用户是否都操作该表的操作权限
-
比如关联的表是否存在,返回的字段是否存在合法等等
-
检测完之后又会有一棵新的解析树
-
优化器
经过解析器和预处理器之后,得到完全合法的解析树,MySQL还会对这棵树进行优化一下
优化器的作用就是根据解析树生成不同的执行计划,然后选择一种最优的执行计划
哪种执行计划执行时成本最小就用哪种
查看上次查询的成本开销
show status like 'Last_query_cost';
-
MySQL的常见优化手段
-
当有多个索引时,决定使用那个索引
-
多表关联时,决定以哪个表为基准表,符合小表驱动大表的准则
-
...
-
-
至于查询计划,我们会在后面的的笔记中详细说到,这里就不再赘述了...
执行器
MySQL 通过分析器知道了你要做什么,通过优化器知道了该怎么做,得到了一个查询计划。于是就进入了执行器阶段,开始执行语句
-
开始执行的时候,要先判断一下你对这个表customer有没有执行查询的权限,如果没有,就会返回没有权限的错误。
-
在工程实现上,如果命中查询缓存,会在查询缓存返回结果的时候,做权限验证
-
-
如果有权限,就使用指定的存储引擎打开表开始查询
-
执行器会根据表的引擎定义,去使用这个引擎提供的查询接口,提取数据
-
比如我们这个例子中的表 customer中,customer_id 字段是主键,那么执行器的执行流程是这样的
-
调用 InnoDB 引擎接口,从主键索引中检索customer_id=14的记录
-
主键索引等值查询只会查询出一条记录,直接将该记录返回客户端
-
-
如果customer_id 不是主键字段,则执行器的执行流程就会变成这样
-
调用 InnoDB 引擎接口取这个表的第一行
-
.判断customer_id 值是不是 14,如果不是则跳过,如果是则将这行缓存在结果集中
-
-
调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行
-
执行器将上述遍历过程中所有满足条件的行组成的结果集返回给客户端
-