针对原生MySQL Query Cache的不足,阿里云进行重新设计和全新实现,推出Fast Query Cache,能够有效提高数据库查询性能。

前提条件

实例版本为MySQL 5.7(内核小版本20200331或以上)。

背景信息

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

MySQL原生Query Cache在设计和实现上存在着较多严重问题:

  • 并发处理较差,在多核情况下,可能并发越高性能降低越严重。
  • 内存管理较差,内存利用率低并且回收不及时,造成内存浪费。
  • 当缓存命中率较低时,性能无提升甚至会出现严重降低。

由于以上问题,MySQL原生Query Cache没有得到广泛应用,在最新版的MySQL 8.0中,取消此功能。阿里云数据库团队对Query Cache进行重新设计和全新实现,解决了以上几个主要问题:

  • 优化并发控制

    取消全局锁同步机制,采用无锁机制,重新设计并发场景下的同步问题,能够充分利用多核的处理能力,保证高并发场景下的性能。

  • 优化内存管理

    取消内存预分配机制,采用更加灵活的动态内存分配机制,及时回收无效的内存,保证内存的真实利用率。

  • 优化缓存机制

    动态检测缓存利用率,实时调整缓存策略,解决命中率偏低或读写混合等场景下的性能降低问题。

相比原生Query Cache,Fast Query Cache可以在不同的业务场景中放心开启,提高查询性能。

开启Fast Query Cache

Fast Query Cache需要配置一定量的内存才能起到良好的效果,可能需要降低InnoDB Buffer Pool的内存空间,将更多内存空间提供给Query Cache。Fast Query Cache目前处于邀请测试阶段,您如果感兴趣,可以提交工单申请开通此功能。

性能比较

在相同场景下,分别测试QC-OFF(关闭Query Cache)、MySQL-QC(开启MySQL原生Query Cache)和RDS-QC(开启Fast Query Cache)的QPS。

  • 测试环境:4核8GB 独享型实例
  • 测试工具:Sysbench
  • 数据量:250MB(25张表,每张表40000条记录)
  • 场景1:全部命中(只读)

    测试场景为Sysbench oltp_point_select,用例中仅包括主键上的点查(point select),将Query Cache设为512MB,内存大于测试数据量,缓存命中率达到99%以上,主要关注不同并发下的性能提升效果。

    表 1. 全部命中(只读)QPS
    并发数 QC-OFF MySQL-QC(相比QC-OFF提升) RDS-QC(相比QC-OFF提升)
    1 7947 8771(10.38%) 9196(15.72%)
    8 61685 65686(6.49%) 74603(20.94%)
    16 102800 73027(-28.96%) 141856(37.99%)
    32 102222 60567(-40.75%) 199209(94.88%)
    64 110230 60216(-45.37%) 218456(98.18%)
    128 111274 62844(-43.52%) 223885(101.20%)
    256 109978 63832(-41.96%) 218692(98.85%)
    512 107379 64866(-39.59%) 211062(96.56%)
    1024 102610 62291(-39.29%) 198787(93.73%)
    全部命中
    说明 测试结果显示,在较高并发的场景下,MySQL原生Query Cache并发处理性能出现较大幅度的降低,Fast Query Cache在各个并发场景下无性能降低,最高时能够提高一倍的QPS。
  • 场景2:高命中率(只读)

    测试场景为Sysbench oltp_read_only,用例中包含返回多条记录的范围查询,将Query Cache设为512MB,内存才相对比较充足,命中率可以达到80%以上,这时主要关注不同并发下的性能提升效果。

    表 2. 高命中率(只读)QPS
    并发数 QC-OFF MySQL-QC(相比QC-OFF提升) RDS-QC(相比QC-OFF提升)
    1 4944 6467(30.82%) 6860(38.77%)
    8 28195 28651(1.62%) 42720(51.52%)
    16 35292 31099(-11.88%) 63227(79.15%)
    32 34067 27610(-18.95%) 63133(85.32%)
    64 35706 27518(-22.93%) 70556(97.61%)
    128 36303 27733(-23.61%) 74146(104.24%)
    256 36386 27738(-23.77%) 75550(107.64%)
    512 36083 27398(-24.07%) 74317(105.96%)
    1024 35077 26861(-23.42%) 71205(103.00%)
    高命中率
    说明 测试结果显示,随着并发数的增加,MySQL原生Query Cache的性能出现明显的降低,Fast Query Cache的性能则会不断提升,最高时能够提高一倍多的QPS。
  • 场景3:低命中率(只读)

    测试场景为Sysbench oltp_read_only,用例中包含返回多条记录的范围查询,将Query Cache设为16MB,内存明显严重不足,缓存命中率只有10%左右,内存不足时会涉及缓存项的大量淘汰,影响性能,这时主要关注不同并发下的性能降低程度。

    表 3. 低命中率(只读)QPS
    并发数 QC-OFF MySQL-QC(相比QC-OFF提升) RDS-QC(相比QC-OFF提升)
    1 4944 4727(-4.38%) 4917(-0.54%)
    8 28195 22542(-20.05%) 27897(-1.06%)
    16 35292 24064(-31.81%) 34625(-1.89%)
    32 34067 21330(-37.39%) 33592(-1.39%)
    64 35706 19791(-44.57%) 35571(-0.38%)
    128 36303 19519(-46.23%) 36055(-0.68%)
    256 36386 19168(-47.32%) 36243(-0.39%)
    512 36083 18420(-48.95%) 35679(-1.12%)
    1024 35077 20168(-42.50%) 34595(-1.37%)
    低命中率
    说明 测试结果显示,MySQL原生Query Cache的性能降低明显,最多出现了接近50%的性能损失,Fast Query Cache优化了低命中率场景,将性能损失控制在2%以内。
  • 场景4:读写混合

    测试场景为Sysbench oltp_read_write,每个事务中都有对表的更新操作,可以认为缓存基本处于失效状态,频繁的更新操作涉及缓存的主动淘汰,理论上会比较影响性能,这时主要关注不同并发下的性能衰减程度。

    表 4. 读写混合QPS
    并发数 QC-OFF RDS-QC(相比QC-OFF提升)
    1 4188 4199(0.27%)
    8 21587 21263(-1.50%)
    16 26224 25956(-1.02%)
    32 27887 27741(-0.52%)
    64 29852 29426(-1.43%)
    128 30024 29724(-1.00%)
    256 29835 29615(-0.74%)
    512 29525 29683(0.54%)
    1024 29905 29512(-1.31%)
    读写混合
    说明 测试结果显示,Fast Query Cache在读写混合场景下不会出现过多的性能降低,整体性能影响控制在2%以内。

实践指南

在缓存数据集大小明确的情况下,例如使用SQL_CACHE关键字对指定表开启Query Cache,可以参照前面的测试进行性能评估。接下来将对Fast Query Cache的使用作一些补充说明。

  • 适用场景指南
    • Fast Query Cache主要目的是提高读操作性能,建议在读多写少的场景下开启,或者使用SQL_CACHE关键字针对读多写少的表开启。如果写多读少,数据的更新非常频繁,可能会出现2%以内的性能降低。
    • 开启Fast Query Cache带来的性能提升和缓存命中率直接相关。在全局开启前建议查看InnoDB Buffer Pool的命中率(命中率 = 1 - Innodb_buffer_pool_reads/Innodb_buffer_pool_read_requests),如果命中率低于80%,则不建议开启。您也可以通过TABLE_STATISTICS表查看表级别的读写比,对读写比高的表通过SQL_CACHE关键字显式开启Fast Query Cache。查询TABLE_STATISTICS表请参见Performance Insight
  • 缓存使用方式(query_cache_type)

    Fast Query Cache完全兼容原生Query Cache的使用方法,可通过query_cache_type参数控制缓存。

    参数名 取值 说明
    query_cache_type OFF 默认值,禁用Fast Query Cache。
    ON 使用Fast Query Cache,可通过SQL_NO_CACHE关键字跳过缓存。
    DEMAND 不启用Fast Query Cache,可通过SQL_CACHE关键字开启。

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

    • 对于更新频繁、写多读少等不适合Query Cache的场景,应将query_cache_type全局设置为OFF。
    • 对于数据量较小、访问模式比较固定、命中率较高的场景,可以将query_cache_type全局设置为ON。
    • 对于数据量较大、访问模式不固定、命中率无法保障的场景,可将query_cache_type设置为DEMAND,仅对指定的语句,通过SQL_CACHE关键字使用Fast Query Cache。
  • 缓存大小(query_cache_size)设置

    query_cache_size和SQL息息相关,如果缓存中有返回多条记录的查询,缓存可能需要是数据量的数倍。如果SQL中不包含范围查询,可以参见以下测试来评估数据量和query_cache_size的关系。

    • 测试环境:4核8GB独享型实例(innodb_buffer_pool_size=6GB)
    • 测试工具:Sysbench
    • 数据量:10GB(100张表,每张表400000条记录)

    测试场景为Sysbench oltp_point_select、64并发、Special分布(20%热点)。测试不同query_cache_size大小对于性能的影响。对应上述的数据量,全量结果集的真实大小为2.5GB。

    表 5. 不同缓存QPS
    query_cache_size(MB) QC-OFF RDS-QC命中率 RDS-QC(相比QC-OFF提升)
    128 104473 45% 110483(5.75%)
    256 104473 72% 128297(22.80%)
    512 104473 82% 137153(31.28%)
    1024 104473 84% 133624(27.90%)
    2048 104473 87% 125766(20.38%)

    对于query_cache_size的设置,可以参见以下建议:

    • 若能够评估结果集大小,query_cache_size可以设置为20% * 结果集大小
    • 若无法准确评估结果集大小,query_cache_size可以设置为20% * innodb_buffer_pool_size
    • 由于内存总量有限,建议query_cache_size和innodb_buffer_pool_size同步调整,避免实例内存耗尽。