MySQL下SQL的执行流程(5.7&8.0)

76 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

MySQL5.7

查看当前数据库版本select version();如下图

image.png

首先我们需要打开查询记录,先查看是否打开show variables like "profiling";或者

select @@profiling;查看是否开启查询记录,开启后可以查看最近15条的执行,如下图

image.png

使用show profile for query query_id即可查看详细的执行计划,如下图

image.png

在这里我们可以看到当前SQL的执行计划,并没有去execute,而是直接将缓存的结果返回,这是因为在MySQL5.7的版本下还存在query_cache_type缓存,并且默认是开启的,使用show variables like "query_cache_type"即可查看是否开启,使用set global query_cache_type = 0/1关闭或开启。

如果此时我们想当前表执行delete、update、insert中的任意一个语句,当前表的高速缓存将全部失效,如下图 我们更新id为6666的记录名称为“掘金课堂”,然后使用之前有缓存的select语句再次去查询,会发现缓存失效了

image.png

执行show profile for query 25;如下图:

image.png

现在缓存中有了,我们再次执行查看,如下图再次命中缓存。

image.png

MySQL8.0

查看当前MySQL版本,如下图

image.png

查看是否还有query_cache_type,如下图可以看到在MySQL8.0里已经将query_cache缓存移除, 很好奇为什么?实际上在MySQL5.7上面演示缓存失效的情况下就可以知道,当缓存表的缓存执行delete、update、insert操作时全表的高速缓存将会失效,这意味着缓存的命中率过低,很鸡肋,只有当很少更新的表类似字典表这种缓存命中率才较高,但是访问率不高啊,而且另一方面类似这种字段表或者变动不大的表,都会在业务层面进行缓存,不会直接请求db,从这方面也可以看出,另一方面缓存本身的命中就很苛刻,要求select语句完全一致,包括参数、大小写、注释、甚至空格,如果包含一些动态的系统变量比如 @host、now()等都会导致缓冲池无法命中。

image.png

剩下的show profiles,show profile等命令都是一样的,补充下在show profile cpu,block io for query qury_id可以查看更多信息,如cpu、io相关,如下图

image.png

总结

****查询缓存是提前把查询结果缓存起来,这样下次不需要执行就可以直接拿到结果。需要说明的是,在 MySQL 中的查询缓存,不是缓存查询计划,而是查询对应的结果。这就意味着查询匹配的 鲁棒性大大降 低 ,只有 相同的查询操作才会命中查询缓存 。两个查询请求在任何字符上的不同(例如:空格、注释、 大小写),都会导致缓存不会命中。因此 MySQL 的 查询缓存命中率不高 。

同时,如果查询请求中包含某些系统函数、用户自定义变量和函数、一些系统表,如 mysql 、 information_schema、 performance_schema 数据库中的表,那这个请求就不会被缓存。以某些系统函数 举例,可能同样的函数的两次调用会产生不一样的结果,比如函数 NOW ,每次调用都会产生最新的当前 时间,如果在一个查询请求中调用了这个函数,那即使查询请求的文本信息都一样,那不同时间的两次 查询也应该得到不同的结果,如果在第一次查询时就缓存了,那第二次查询的时候直接使用第一次查询 的结果就是错误的!

此外,既然是缓存,那就有它 缓存失效的时候 。MySQL的缓存系统会监测涉及到的每张表,只要该表的 结构或者数据被修改,如对该表使用了 INSERT 、 UPDATE 、 DELETE 、 TRUNCATE TABLE 、 ALTER TABLE 、 DROP TABLE 或 DROP DATABASE 语句,那使用该表的所有高速缓存查询都将变为无效并从高 速缓存中删除!对于 更新压力大的数据库 来说,查询缓存的命中率会非常低。****