惊,MySQL8居然抛弃了查询缓存!!!
英雄也有落幕时,MySQL8.0 已经删除了查询缓存,Query Cache 便正式退出了历史舞台,实际上在5.7 版本中已经可以通过缺省值query_cache_type控制,且默认是处于关闭状态。在官方文档中也是标注为了Deprecated 。
经历过如此多版本迭代了查询缓存,官方为什么要抛弃呢?设计的初衷又是什么呢?那么接下来我就带领大家来一步一步深入学习。
查询缓存
The query cache stores the text of a SELECT statement together with the corresponding result that was sent to the client. If an identical statement is received later, the server retrieves the results from the query cache rather than parsing and executing the statement again. The query cache is shared among sessions, so a result set generated by one client can be sent in response to the same query issued by another client. The query cache can be useful in an environment where you have tables that do not change very often and for which the server receives many identical queries. This is a typical situation for many Web servers that generate many dynamic pages based on database content. The query cache does not return stale data. When tables are modified, any relevant entries in the query cache are flushed.
查询缓存存储 SELECT 语句的文本以及发送到客户端的相应结果。如果稍后收到相同的语句,服务器将从查询缓存中检索结果,而不是再次解析和执行该语句。查询缓存在会话之间共享,因此可以将一个客户机生成的结果集发送给另一个客户机发出的相同查询。
查询缓存在这样的环境中非常有用,即表不经常更改,并且服务器收到许多相同的查询。对于许多基于数据库内容生成许多动态页面的 Web 服务器来说,这是一种典型的情况。
查询缓存不返回过期数据。修改表时,将刷新查询缓存中的任何相关条目。
摘自MySQL官方文档: https://docs.Oracle.com/cd/E17952_01/mysql-5.6-en/query-cache.html
工作原理
在解析之前将传入查询与查询缓存中的查询进行比较,因此查询缓存认为以下两个查询是不同的:
SELECT * FROM tbl_name Select * from tbl_name
虽然两条查询语句是意义是一样的,但是mysql会为这条SQL生成一个hash值。尽管是小写和大写的区别,但还是会被认定为2条查询语句。
之后就是将hash值和查询结果缓存在Query Cache 中,后续查询语句都会通过hash值对比如果一致就返回缓存结果,否则就去数据库中查询。
官方设计之初就是考虑用此来提升查询效率,因为Query Cache 区域是放在内存中,如果业务中存在大量的重复请求查询,那也就不用去进行SQL解析、优化、硬盘查询等一系列操作了。性能的提升是非常巨大的。
看上去是非常不错,那为什么官方要将至删除呢?
- 首先在前面也和大家讲到过,通过sql语句对比,尽管大小写不同缓存还是无法命中,但实际我们在生产环境中,有很多业务实际一致返回结果也一致,但是由于这种比较苛刻的要求,会导致无法命中。
- 第二点就是缓存过期策略也是非常苛刻,我们只要对表中数据进行修改也会导致缓存实效,比如说增删改语句,表结构调整语句等等。上面特性也就说明了,只有在读远大于写的场景下,查询缓存才能发挥价值。对于读写比例毕竟均衡或者读少但是写多的场景,基本上查询环境就没什么太大价值了。
- 第三点分区表禁用,如果我们的数据表使用了分区,查询环境会直接禁用无法生效。
- 第四点当开启Query Cache选项后,如果查询请求没有命中Query Cache时,MySQL会需要额外的性能开销去处理结果集,写入Query Cache中,最糟糕的情况下,这个额外的性能开销是13%,但实际场景中的情况会更加的复杂,通常情况下,额外的性能开销会低于该值,但这仍是一笔无谓的性能损耗。
- SQL中使用了特定函数也会导致不走查询缓存,比如说now()等等。
我们综上对比其实就可以产出,MySQL对查询缓存的限制非常多,但是实际生产中很多SQL都会触发限制条件不走查询缓存。MySQL在综合考虑之下关闭了查询缓存。官方也给出了一些解释
Assuming that scalability could be improved, the limiting factor of the query cache is that since only queries that hit the cache will see improvement; it is unlikely to improve predictability of performance. For user facing systems, reducing the variability of performance is often more important than improving peak throughput:
假设可伸缩性可以得到改进,那么查询缓存的限制因素是,因为只有触及缓存的查询才会得到改进; 所以不太可能提高性能的可预测性。对于面向用户的系统,降低性能的可变性往往比提高峰值吞吐量更为重要:
MySQL官方团队对于在8.0版本中彻底移除Query Cache的决策做出了如上的解释,并给出了所替代的解决方案建议——使用第三方工具客户端缓存ProxySQL 来代替Query Cache。
如下图所示,MySQL官方给出了使用ProxySQL 对比原生Query Cache 性能报告,从图中可以清晰的看到,ProxySQL 的查询性能完胜原生的Query Cache。