从遇到的一个性能问题学习mysql的查询缓存

最近在测试性能问题的时候,遇到一个加压TPS无法上去的接口;接口很简单,就是触发一个mysql的查询语句并放回。TPS在加压后上不去;观察服务节点和数据库节点的资源使用情况都正常。一时分析不出是什么原因。

猜测是不是命中了数据库缓存导致的。引起对mysql缓存的了解。记录下一些学习的点,零散。问题还没找到,等找到了再记录下吧。

首先是存储引擎:

mysql有多种存储引擎,但是我遇到的是innodb。所以就基于innodb学习下它的一些查询缓存相关的。innodb采用了聚簇索引,提高了主键查询的性能,同时要求2级索引必须包含主键,也就加大了索引文件。它有很多优点,这里不列举,去看看N多大神的帖子也就知道了。

什么是查询缓存:

是指mysql在内存中缓存了完整的select语句的结果。不过select语句中不能带函数和变量,否则就无法匹配到,会造成缓存无法命中。单查询命中缓存时会立刻返回结果,跳过了解析,优化,执行的阶段。也就是这点,我在观察性能脚本执行过程中,show full processlist没看到执行的语句,IO也比较低。所以产生了这种怀疑,只是目前还没找到方法去证明是命中缓存导致的测试现象。

mysql是怎么判断是否命中缓存:

首先mysql会将第一次查询的结果放在一个引用表中,通过哈希引用;当一个查询过来的时候,会通过一些判断条件去判断。当命中时,就不会去解析这条sql,而是按照缓存结果返回。但是sql语句中有任何不确定的函数,变量,和不统一的写法(空格之类的不一致)都无法命中缓存。

缓存的应用只有性能的提升就没有消耗?

答案是否定的,在提升查询的性能的同时,其实会带来读写的消耗:

1、读操作的时候,会先去检查是否会命中缓存

2、如果查询能缓存,则会在返回结果后,检查这个查询语句是否已经缓存了,如果没有缓存,则写入缓存

3、对于数据库的写操作,由于可能改变原来查询的结果;这时候需要先去将对应表的缓存设置为失效的状态。如果缓存大或者碎片过多,这消耗了系统的性能。

如何用内存的:

在数据库在启动创建数据库缓存时,根据配置申请一块内存块,初始化后用于存储数据缓存。主要包括数据块索引,数据,状态等的维护。

怎么判断是否需要开启查询缓存?

最直接的方法,分别在开启和不开启的情况下进行性能测试。然后就是决策,因为在某些sql的查询性能的提升后,可能同时会带来其他sql的执行性能下降。这时候需要决策哪个更重要。

哪些场景适合开启查询缓存:

那种查询基础数据量很大,结果却返回很小的。例如count(),max(),等。

如何判断缓存命中率:

可以试试看两个值,任何查询,要么使Qcache_hits增加,要么使Com_select值增加。可以通过(Qcache_hits/(Qcache_hits+Com_select))进行计算。至于这个命中率怎么样才是好的,却没有定论。需要根据自己的系统决定。唯一的一条原则就是,它带来的性能提升比它带来的性能损耗要高即可。

至于缓存未命中:

缓存未命中的原因主要有:

1、查询无法缓存

2、第一次查询

3、内存不足导致之前的缓存被清理了,即失效了。

缓存的配置:

缓存的使用需要在mysql的配置文件中进行配置:

1、query_cache_type:是否打开查询缓存:ON,OFF,DEMAND,其中DEMAND是只有查询语句中明确洗了SQL_CACHE才放入查询缓存。

2、query_cache_size:查询缓存使用的总内存大小

3、query_cache_min_res_unit:查询缓存中分配内存块是最小的单位

4、query_cache_limit:能缓存的最大内存

5、query_cache_wlock_invalidate:如果某个数据表被其他的链接锁住,是否仍然从查询缓存中返回结果。

Innodb和缓存:

innodb有事务机制,通过事务ID的判断来判断是否该查询能用缓存。只有当前的事务ID小于即将执行的事务ID才给该事务使用缓存。同时这个表如果有任何的锁,都不能用缓存。即加锁的事务不允许用查询缓存。

看到这里好像差不多了,但是我发现原来被测系统的缓存时OFF状态。那是不是还有其他缓存机制?

有的:

包括应用层缓存,handlerSocket与memchached三种。还没弄懂,夜深。后面继续。

所以,那个性能问题到底是什么问题,目前主要还是觉得读的缓存。未完待续。。。

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页