数据库内核月报

数据库内核月报 - 2020 / 05

AliSQL · 引擎特性 · Fast Query Cache 介绍

Author: 翊云

背景介绍

Query Cache(查询缓存)是 MySQL 为了提高查询性能而实现的一种缓存策略,基本思想是:对于每个符合条件的查询语句,直接对结果集进行缓存;当下次查询命中时,直接从缓存中取出对应的结果集返回,不需要经过 MySQL 的 Parser / Optimize / Execute / Storage Engine 等复杂的代码执行路径;通过节约 CPU 资源来达到查询加速的目标,是一项非常实用的技术。

QC

但是 MySQL 社区对于 Query Cache 设计和实现上不够理想,存在较多严重的问题,主要包括:

基于以上问题,MySQL 上的 Query Cache 功能一直没有得到很好的应用,在最新的 MySQL 8.0 版本中,社区直接移除了相关的代码,去掉了此功能。

Fast Query Cache

通过对 Query Cache 的深入分析,阿里云数据库团队对 Query Cache 进行了重新设计,实现了一种更优雅的 Query Cache 机制,从以下几个方面解决了上述问题:

相比原生的 Query Cache,Fast Query Cache 在保证缓存命中时查询性能的同时,充分控制了缓存带来的副作用,用户可以在不同的业务场景中安心地开启 Fast Query Cache 功能,对查询进行加速。

性能测试

测试环境

高命中率场景

测试场景为 oltp_read_only,用例中包含返回单条记录的点查和返回多条记录的范围查询,将 Query Cache 的 query_cache_size 参数设置为 512MB,内存比较充足,整体命中率可以达到 80%+。此场景下主要关注不同并发下 Fast Query Cache 的性能提升效果。

并发数 QC-OFF MySQL-QC RDS-QC MySQL-QC 性能提升 RDS-QC 性能提升
1 5099 6467 7022 26.83% 37.71%
8 28782 28651 45017 -0.46% 56.41%
16 35333 31099 66770 -11.98% 88.97%
32 34864 27610 67623 -20.81% 93.96%
64 35503 27518 75981 -22.49% 114.01%
128 35744 27733 80396 -22.41% 124.92%
256 35685 27738 80925 -22.27% 126.78%
512 35308 27398 79323 -22.40% 124.66%
1024 34044 26861 75742 -22.10% 122.48%

测试结果显示,随着并发数的增加,MySQL 原生 Query Cache 的性能出现明显退化;Fast Query Cache 的性能则会不断提升,峰值性能提升能够达到 120%+。

低命中率场景

测试场景为 oltp_read_only,用例中包含返回单条记录的点查和返回多条记录的范围查询,将 Query Cache 的 query_cache_size 参数设置为 16MB,内存明显不足,缓存命中率只有 10% 左右。此场景下内存不足会导致缓存项的大量淘汰,影响性能,主要关注不同并发下 Fast Query Cache 的性能退化程度。

并发数 QC-OFF MySQL-QC RDS-QC MySQL-QC 性能提升 RDS-QC 性能提升
1 5004 4727 5199 -5.54% 3.90%
8 28795 22542 28578 -21.72% -0.75%
16 35455 24064 35682 -32.13% 0.64%
32 34526 21330 35871 -238.22% 3.90%
64 35514 19791 36051 -44.27% 1.51%
128 35983 19519 36253 -45.75% 0.75%
256 35695 19168 36337 -46.30% 1.80%
512 35182 18420 35972 -47.64% 2.25%
1024 33915 20168 34546 -40.53% 1.86%

测试结果显示,内存不足时,MySQL 原生 Query Cache 的性能退化更加明显,最多出现了接近 50% 的性能损失;Fast Query Cache 充分平衡了此种场景,不会带来任何额外的性能损失。

读写混合场景

测试场景为 oltp_read_write,用例中每个事务内都有对表的更新操作将 Query Cache 的 query_cache_size 参数设置为 512MB,内存相对比较充足。此场景下缓存基本处于失效状态,主要关注不同并发下 Fast Query Cache 的性能衰减程度。

并发数 QC-OFF RDS-QC RDS-QC 性能提升
1 4152 4098 -1.30%
8 21359 21195 -0.77%
16 26020 25548 -1.81%
32 27595 26996 -2.17%
64 29229 28733 -1.70%
128 29265 28828 -1.49%
256 29911 29616 -0.99%
512 29148 28816 -1.14%
1024 29204 28824 -1.30 %

测试结果显示,Fast Query Cache 在读写混合场景下不会造成过多的性能衰减,整体对性能的影响控制在 2% 以内。

实践指南

适用场景

Fast Query Cache 的目的是提高读操作的性能,所以建议在读多写少的场景下进行开启,或者使用 SQL_CACHE hint 对读多写少的表单独开启。如果写多读少,数据的更新非常频繁,不建议开启 Query Cache 功能。

需要注意,开启 Fast Query Cache 带来的性能提升和缓存命中率直接相关。在全局开启前建议查看一下 InnoDB Buffer Pool 的命中率情况(100 - Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests * 100),如果 Buffer Pool 的命中率低于80%,则不建议开启。表级的读写比可以参照 AliSQL 提供的对象统计功能(TABLE_STATISTICS)中的数据,对读写比较高的表通过 SQL_CACHE hint 显式开启 Fast Query Cache。

使用方式

Fast Query Cache 完全兼容 MySQL 原生 Query Cache 的使用逻辑,可通过 query_cache_type 参数控制 Query Cache 的开启方式:

query_cache_type 参数支持会话级修改,用户可以根据真实业务场景进行灵活设置:

缓存大小设置

Fast Query Cache 的性能提升效果和 Cache 的命中率紧密相关,具体的测试情况如下:

query_cache_size(MB) QC-OFF RDS-QC RDS-QC 命中率 RDS-QC 性能提升
64 98236 99440 22% 1.23%
128 98236 114155 45% 16.21%
256 98236 140668 72% 43.19%
512 98236 151260 82% 53.98%
1024 98236 153866 84% 56.63%
2048 98236 159597 87% 62.46%
4096 98236 169412 92% 72.45%

测试结果显示,Fast Query Cache 在各种 query_cache_size 的设置下都不会引起性能退化。由于测试场景是主键点查,所以对缓存命中率要求比较高,Fast Query Cache 的性能提升随着命中率的提高不断提升,当命中率达到 90%+ 时,整体提升效果比较明显。注意:由于阿里云 RDS MySQL 已经对主键点查做了优化,所以 Fast Query Cache 在主键点查下的性能提升不如范围查询明显;对于范围查询或带 ORDER BYGROUP BY 等关键字的查询语句,当缓存命中率低于90%时,也能节约大量的 CPU,带来较大的性能提升。

为了保证 Cache 的命中率,对于 query_cache_size 的设置,可以参考以下建议:

此外,用户也可以通过查看 Fast Query Cache 提供的状态值信息,查看当前的真实命中率,根据情况动态地对 query_cache_size 进行调整。

总结

Query Cache 的根本目的是用 Memory 换 CPU 和 IO,通过缓存结果集,减少 MySQL 真实执行查询的 CPU 和 IO 消耗。对于读多写少、数据更新不频繁的场景,使用好 Query Cache 可以取得非常好的性能。Fast Query Cache 已在阿里云 RDS MySQL 5.7 最新版本发布,欢迎试用。