前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >MySQL查询缓存

MySQL查询缓存

原创
作者头像
lakezhong
修改于 2020-02-04 03:16:39
修改于 2020-02-04 03:16:39
6.5K0
举报
文章被收录于专栏:lakezhong的专栏lakezhong的专栏

MySQL查询缓存,query cache,是MySQL希望能提升查询性能的一个特性,它保存了客户端查询返回的完整结果,当新的客户端查询命中该缓存,MySQL会立即返回结果。

要了解MySQL查询缓存,最好先对MySQL查询执行流程有个基本概念。图1展示了MySQL服务器执行客户端查询查询请求的执行流程。

  1. 客户端发送一条查询给MySQL服务器;
  2. MySQL服务器开启了查询缓存开关时,服务器先检查查询缓存,如果命中了缓存,则立即返回存储在缓存中的结果,否则进入下一个阶段(缓存开关关闭或者未命中);
  3. MySQL服务器进行SQL解析、预处理、再由优化器生成对应的执行计划;
  4. 执行优化器生成的执行计划,调用存储引擎的API来执行查询;
  5. 将结果返回给客户端。在这个阶段也会将查询结果存放到查询缓存中;
图1 MySQL查询执行路径
图1 MySQL查询执行路径

很明显,设置查询缓的目的就是为了减少MySQL服务器重复执行相同的查询,减小服务器压力。而且查询缓存对客户端是完全透明的,应用程序无须关心MySQL是通过查询缓存返回的结果还是实际执行返回的结果。

虽然查询缓存对客户端透明,但在做查询时还是需要了解查询缓存的工作原理,才能更有效地利用它。主要包括:“MySQL如何判断缓存命中”“MySQL如何失效缓存”“查询缓存的内存管理”。

MySQL如何判断缓存命中

MySQL判断缓存命中的方法很简单:缓存存放在一个引用列表中,通过一个哈希值引用,这个哈希值包括了如下因素:查询本身、当前要查询的数据库、客户端协议的版本等一些其他可能会影响返回结果的信息。

当判断缓存是否命中时,MySQL不会解析、“正规化”或者参数化查询语句,而是直接使用SQL语句和客户端发送过来的其它原始信息。任何字符上的不同,例如空格、注释,都会导致不能命中缓存。所以在编写SQL语句时,需要特别注意这点。

查询缓存中的缓存数据是在查询执行引擎返回查询结果的阶段设置的,但不是所有的查询都会被缓存。查询语句中如果包含一些不确定的数据时,查询结果是不会被缓存的,例如查询语句中包含:NOW()、CURRENT_DATE()等。因为每次执行这类带了不确定数据的查询所返回结果可能是不同的。

MySQL如何失效缓存

写操作会导致查询缓存失效。因为对某个表写入数据的时候,对这个表查询的返回结果可能会发生变化,前面说过MySQL不会解析查询语句,MySQL实现上就是简单粗暴的把这个表的所有缓存都设置失效。

查询缓存的内存管理

查询缓存是完全存储在内存中的。除此之外,还需要缓存很多别的管理维护相关的数据,用来确定哪些内存目前是可用的、哪些是已经用掉的、哪些用来存储数据表和查询结果之前的映射、哪些用来存储查询字符串和查询结果。

MySQL用于查询缓存的内存被分成一个个的数据块,数据块是变长的。每个数据块中,存储了数据块类型、大小和存储数据本身,还外加指向前一个和后一个数据块的指针。数据块类型有:存储查询结果、存储查询和数据表的映射、存储查询文本等。

服务器启动时,先初始化查询缓存需要的内存。这个内存池初始是一个完整的空闲块。当有查询结果需要缓存的时候,MySQL先从大的空间块中申请一个数据块用于存储数据。这个数据块的大小需要大于参数query_cache_min_res_unit的配置,虽然有时实际需要的内存空间并没有那么大。这么做的原因是:MySQL是边计算边返回查询结果的,也就意味着MySQL无法预知查询结果到底有多大,而分配内存块是个非常慢的操作,所以设定了一个申请下限,权衡时间和空间,最大限度满足大多数查询需要申请内存块的需求。

当需要缓存一个查询结果的时候,先选择一个尽可能小的内存块(也可能选择较大的,看不同查询的策略),然后将结果存入其中。如果内存块全部用完了,但仍有剩余数据需要存储,MySQL会申请一个新的数据继续存储查询结果。当查询完成时,MySQL会释放剩余未用完的内存空间。

图2展示了上述的内存分配过程。类似操作系统中的内存管理,当并行多次分配内存之后,数据块之间会产生内存碎片。当query_cache_min_res_unit设置不合理时,会导致查询缓存内存池的内存利用率低。

图2 查询缓存内存分配示意
图2 查询缓存内存分配示意

MySQL查询缓存的目的是为了提升查询性能,但它本身也是有性能开销的。需要在合适的业务场景下(读写压力模型)使用,不合适的业务场景不但不能提升查询性能,查询缓存反而会变成MySQL的瓶颈。

查询缓存的开销主要有:

  1. 读查询在开始前必须先检查是否命中缓存;
  2. 如果这个读查询可以被缓存,那么当完成执行后,MySQL若发现查询缓存中没有这个查询,会将其结果存入查询缓存,这会带来额外的系统消耗;
  3. 当向某个表写入数据的时候,MySQL必须将对应表的所有缓存都设置失效。如果查询缓存非常大或者碎片很多,这个操作就可能带来很大的系统消耗。

通常来说在数据库写占比较大的情况,查询缓存的开销会大于性能提升带来的好处。但大多数业务数据库写都占了较大比例,通过测试发现开启查询缓存会降低MySQL的性能。所以大多数云厂商提供的MySQL实例默认是关闭了查询缓存开关的。例如腾讯云MySQL,查询缓存开关见图3。

图3 腾讯云MySQL实例默认查询缓存是关闭的
图3 腾讯云MySQL实例默认查询缓存是关闭的

查询缓存提供了一些配置参数。参数说明如下:

query_cache_type

是否打开查询缓存。可以设置OFF、ON或DEMAND、DEMAND表示只有在查询语句中明确写入sql_cache的语句才放入查询缓存。这个变量可以是会话级别的也可以是全局级别的。

query_cache_size

查询缓存使用的总内存空间,单位是字节。这个值必须是1024的整倍数,否则实际分配的数据会和指定的大小有区别。

query_cache_min_res_unit

在查询缓存中分配内存块时的最小单位。

query_cache_limit

MySQL能够缓存的最大查询结果。如果查询结果大于这个值,则不会被缓存。因为查询缓存在数据生成的时候就开始尝试缓存数据,所以只有当结果全部返回后,MySQL才知道查询结果是否超出限制。

如果超出,MySQL则增加状态值qcache_not_cached,并将结果从查询缓存中删除。如果你实现知道有很多这样的情况发生,那么建议在查询语句中加入sql_no_cache来避免查询缓存带来的额外消耗。

query_cache_wlock_invalidate

如果某个数据表被其他的链接锁住,是否仍然从查询缓存中返回结果。这个参数默认是OFF,这可能在一定程序上会改变服务器的行为,因为这使得数据库可能返回其他线程锁住的数据。将参数设置成ON,则不会从缓存中读取这类数据,但是这可能会增加锁等待。对于绝大多数应用来说无需注意这个细节,默认的通常没有问题。

MySQL查询缓存虽本意上是提升查询性能,但大多数情况下它反而会成为性能瓶颈,所以我们大多数时候都是把这个特性关闭的。我们也有非常多的查询缓存的替代方案,比如redis,缓存由业务层来处理。

基于这点,在MySQL8.0版本发布时已经把查询缓存特性给去掉了。虽然以后用不上查询缓存了,但是了解了解它的原理和问题还是挺有好处的。

参考文档:

  1. 《高性能MySQL》
  2. MySQL 5.7/8.0 Reference Manual

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
Oracle Linux 8.0 静默安装Oracle 19C
环境准备工具目前不支持OL8,所以需要手动安装,首先设置内核参数,在/etc/sysctl.conf追加
星哥玩云
2022/08/18
2.6K0
Oracle Linux 8.0 静默安装Oracle 19C
【静默】在RHEL 6.5上静默安装Oracle 18c
今天小麦苗给大家分享的是【静默】在RHEL 6.5上静默安装Oracle 18c。
AiDBA宝典
2019/09/29
9950
【静默】在RHEL 6.5上静默安装Oracle 18c
Oracle 19c standalone(单机ASM)静默安装
记录一下Oracle 19c standalone(单机ASM)静默安装的流程,方便遇到这个场景的时候可以快速部署上。以下配置经过测试环境多次试错得出,如果有相同环境,改改ip主机名磁盘组应该就能直接用。
甚至熊熊
2022/03/30
3K0
【DB宝7】如何在Docker容器中一步一步安装配置Oracle19c的ASM+DB环境
CentOS 7安装Docker: https://docs.docker.com/engine/install/centos/
AiDBA宝典
2020/07/16
3.6K0
【DB宝7】如何在Docker容器中一步一步安装配置Oracle19c的ASM+DB环境
Oracle 11g静默安装简明版
$ more /u02/soft/database/response/db_install.rsp
Alfred Zhao
2019/05/24
1.3K0
Linux 静默安装安装单机 Oracle 19C 数据库
确保虚拟机已经挂载 ISO 镜像之后,通过 mount 挂载镜像源到本地 /mnt 目录下:
用户8006012
2022/06/20
4.5K2
Ubuntu 18.04安装Oracle 11.2.0.4单机
1、我自己尝试了Ubuntu 14.04,Ubuntu 16.04,Ubuntu 18.04,Ubuntu 20.04,Ubuntu 22.04,这几个版本安装Oracle 11.2.0.4,都能安装成功,基本步骤一样,在Ubuntu 14.04,Ubuntu 16.04安装过程一样;在Ubuntu 18.04,Ubuntu 20.04,Ubuntu 22.04安装过程一样,不过需要把gcc进行降级处理,其它过程都一样;。
AiDBA宝典
2023/04/27
2.1K0
Ubuntu 18.04安装Oracle 11.2.0.4单机
OL8静默安装Oracle EMCC 24ai (24.1)
可以使用非 CDB 数据库或 PDB。这里我们使用名为“emcdb”的 CDB 和名为“emrep”的 PDB。
Yunjie Ge
2024/12/20
1890
OL8静默安装Oracle EMCC 24ai (24.1)
静默安装Oracle Database 18c
系统环境:Oracle Linux 7(OL7) 一、首先设置主机名和ip,修改/etc/hosts (很简单,不赘述) 二、Oracle安装先决条件 执行自动设置或手动设置以完成基本先决条件。 1、自动设置 如果您计划使用“oracle-database-preinstall-18c”软件包来执行所有先决条件设置,请发出以下命令。 #yum install -y oracle-database-preinstall-18c 它进行全面更新,但严格来说这并不是必需的。 #yum update -y
孙杰
2019/10/29
9360
[Oracle-> MySQL] Oracle通过dblink连接MySQL--Oracle 19c连接到MySQL 5.7
今天小麦苗给大家分享的是[Oracle-> MySQL] Oracle通过dblink连接MySQL--Oracle 19c pdb连接到MySQL 5.7。
AiDBA宝典
2019/09/29
3.3K0
[Oracle-> MySQL] Oracle通过dblink连接MySQL--Oracle 19c连接到MySQL 5.7
Oracle 11g RAC 原地升级到 19c
记得去年初的一段时间内,总是在进行数据库 19c 的升级,安装,测试工作,当时不知怎的,有一个特殊的要求就是原地升级 11g RAC 到 19c,刚好操作系统版本以及 JDK 均满足要求,就当学习了,顺便将第一次的测试步骤大概记录了下来,便有了这篇文章。
JiekeXu之路
2022/12/07
2.2K0
Oracle 11g RAC 原地升级到 19c
Oracle 19C 静默安装 GoldenGate
https://edelivery.oracle.com/osdc/faces/SoftwareDelivery
OrangeDBM
2023/09/06
3730
【DG】Oracle 19c使用dbca来搭建物理DG(12cR2可以使用但主库必须是单机非CDB的库,18c无限制)
Using DBCA to Create a Data Guard Standby
AiDBA宝典
2019/09/29
1.5K0
基于CentOS 7静默安装Oracle 11gR2单实例数据库
本文记录从无到有部署一个CentOS 7+Oracle 11gR2单实例,做为主要学习试验环境,毕竟只有敲过并运行过的代码才是属于自己的,光看书是看不到多少知识的。
星哥玩云
2022/08/17
7070
基于CentOS 7静默安装Oracle 11gR2单实例数据库
实战:如何在 LINUX 8.0 上安装 Oracle 11.2.0.4(文内有快速配置安装脚本)
写这个测试的主要原因是前一阵群里大佬们一直在讨论如何在REDHAT8.0上安装ORACLE 11G,我还好奇了,现在一般不是都用7.9来跑11G么
JiekeXu之路
2024/04/15
1.3K0
实战:如何在 LINUX 8.0 上安装 Oracle 11.2.0.4(文内有快速配置安装脚本)
【DB宝24】在Oracle 19c中创建容器数据库(1)--DBCA静默创建CDB
从本节开始,麦老师将依次讲解使用DBCA静默创建CDB 、DBCA图形化界面创建CDB、手动创建CDB,即使用create database来创建CDB 、duplicate a CDB、Using DBCA to Duplicate a CDB这5种方式来创建CDB。
AiDBA宝典
2020/10/29
3.3K0
【DB宝24】在Oracle 19c中创建容器数据库(1)--DBCA静默创建CDB
centos7下静默安装oracle11G图解配置 2
本文是《centos7下静默安装oracle11G图解配置》中第二篇。因linux下安装Oracle太过繁琐,如果写在一篇文章中,太长了。本文主要讲解安装前环境配置。
凯哥Java
2019/06/30
1.5K1
在Arm架构上使用Oracle数据库
“ June 28, 2023 ,Oracle发布了基于Arm架构的Oracle数据库版本,姚远老师实验了一下,在海思的鲲鹏CPU上安装成功!。”
姚远OracleACE
2023/09/23
1.9K0
在Arm架构上使用Oracle数据库
CentOS 6.10静默安装Oracle 11G详细教程
平台:CentOS 6.10 x64 带图形 配置4G 4核心cpu 200G硬盘
星哥玩云
2022/08/17
4240
CentOS 6.10静默安装Oracle 11G详细教程
Oracle 19c RAC 遇到的几个问题
Oracle19c 作为长期支持的大版本,是很多公司和个人选择的主流数据库版本,很多公司新上线的系统也都是以 19C 为主,也有很多企业渐渐地迁移数据库到19C,11204 版本已经逐渐退出了舞台。下面对 Oracle 19C版本遇到的几个最主要的问题做个简单介绍。
JiekeXu之路
2022/03/31
1.4K0
Oracle 19c RAC 遇到的几个问题
推荐阅读
相关推荐
Oracle Linux 8.0 静默安装Oracle 19C
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档