mysql的query_cache误区详解

本文章详细的介绍了关于大家在使用mysqlquery_cache认识误区以及后面详细的介绍了mysql的query_cache的用法及优点。

一直以来,对于的query_cache,在网上就流行着这样的说法,“对于mysql的query_cache键值就是mysql的query,所以,如果在query中有任何的不同,包括多了个空格,都会导致mysql认为是不同的查询”,其实,这一种说法是不完全正确的。首先第一点,mysql的query_cache的键值并不是简单的query,而是query加databasename加flag。这个从中就可以看出。在这里不做重点描述,后续可以针对于这一点再具体分析。重要的是第二点,是不是加了空格,mysql就认为是不同的查询呢?实际上这个是要分情况而言的,要看这个空格加在哪。 如果空格是加在query之前,比如是在query的起始处加了空格,这样是丝毫不影响query cache的结果的,mysql认为这是一条query, 而如果空格是在query中,那会影响query cache的结果,mysql会认为是不同的query。

下面我们通过实验及源码具体分析。首先,我们先试验一下:

首先,我们看一下mysql query_cache的状态:

首先,我们可以确认,mysql的query_cache功能是打开的。

其次,我们看一下状态:

因为这个db是新的db,所以hits,inset都为0,现在我们执行一条语句:

状态变为:

可以看到,执行一条select后,现在的qcache状态为,insert+1,这样我们就可以推断出,现在刚才那条select语句已经加入了qcache中。那我们现在再将刚才那条sql前面加上空格,看看会怎样呢?

请注意,这条sql,比刚才那条sql前面多了一个空格。

按照网上的理论,这条sql应该会作为另一个键而插入另一个cache,不会复用先前的cache,但结果呢?

稿定AI社区 稿定AI社区

在线AI创意灵感社区

稿定AI社区 60 查看详情 稿定AI社区

我们可以看到,hits变为了1,而inserts根本没变,这就说明了,这条在前面加了空格的query命中了没有空格的query的结果集。从这,我们就可以得出结论,网上先前流传的说法,是不严谨的。

 

那究竟是怎么回事呢?到底应该如何呢?为什么前面有空格的会命中了没有空格的query的结果集。其实,这些我们可以通过源码获得答案。

翻看下mysql的源码,我这翻看的是5.1的,在send_result_to_client(这个函数既是mysql调用query_cache的函数)这个函数里面有这样一段,

 

 /

 代码如下复制代码

*
 Test if the query is a SELECT
 (pre-space is removed in dispatch_command).

 First ‘/’ looks like comment before command it is not
 frequently appeared in real life, consequently we can
 check all such queries, too.
 */
    if ((my_toupper(system_charset_info, sql[i])     != ‘S’ ||
         my_toupper(system_charset_info, sql[i + 1]) != ‘E’ ||
         my_toupper(system_charset_info, sql[i + 2]) != ‘L’) &&
        sql[i] != ‘/’)
    {
      DBUG_PRINT(“qcache”, (“The statement is not a SELECT; Not cached”));
      goto err;
    }

这段代码,是在检验语句是否为select语句,重点是上面那段注释。特别是括弧中的,pre-space is removed in dispatch_command,也就是说,在语句开始之前的多余的空格已经被处理过了,在dispache_command这个函数中去掉了。

我们看下dispache_command这个方法,在这个方法里有这样一段:

 代码如下复制代码  if (alloc_query(thd, packet, packet_length))
      break;                    // fatal error is set
    char *packet_end= thd->query() + thd->query_length();
    /* ‘b’ stands for ‘buffer’ parameter’, special for ‘my_snprintf’ */
    const char* end_of_stmt= NULL;

在这里,会调用alloc_query方法,我们看下这个方法的内容:

 代码如下复制代码

bool alloc_query(THD *thd, const char *packet, uint packet_length)
{
  char *query;
  /* Remove garbage at start and end of query */
  while (packet_length > 0 && my_isspace(thd->charset(), packet[0]))
  {
    packet++;
    packet_length–;
  }
  const char *pos= packet + packet_length;     // Point at end null
  while (packet_length > 0 &&
     (pos[-1] == ‘;’ || my_isspace(thd->charset() ,pos[-1])))
  {
    pos–;
    packet_length–;
  }
  /* We must allocate some extra memory for query cache

 The query buffer layout is:
 buffer :==
  The input statement(s)
 ‘’ Terminating null char (1 byte)
  Length of following current database name (size_t)
  Name of current database
  Flags struct
 */
  if (! (query= (char*) thd->memdup_w_gap(packet,
                                          packet_length,
                                          1 + sizeof(size_t) + thd->db_length +
                                          QUERY_CACHE_FLAGS_SIZE)))
      return TRUE;
  query[packet_length]= ‘’;
  /*
 Space to hold the name of the current database is allocated. We
 also store this length, in case current database is changed during
 execution. We might need to reallocate the ‘query’ buffer
 */
  char *len_pos = (query + packet_length + 1);
  memcpy(len_pos, (char *) &thd->db_length, sizeof(size_t));

  thd->set_query(query, packet_length);

  /* Reclaim some memory */
  thd->packet.shrink(thd->variables.net_buffer_length);
  thd->convert_buffer.shrink(thd->variables.net_buffer_length);

  return FALSE;
}

这个方法在一开始就会对query进行处理(代码第4行),将开头和末尾的garbage remove掉。

大部分的 MySQL 分发版本中,Query Cache 功能默认都是打开的,我们可以通过调整 MySQL Server 的参数选项打开该功能。主要由以下5个参数构成:

query_cache_limit:允许 Cache 的单条 Query 结果集的最大容量,默认是1MB,超过此参数设置的 Query 结果集将不会被 Cache
query_cache_min_res_unit:设置 Query Cache 中每次分配内存的最小空间大小,也就是每个 Query 的 Cache 最小占用的内存空间大小
query_cache_size:设置 Query Cache 所使用的内存大小,默认值为0,大小必须是1024的整数倍,如果不是整数倍,MySQL 会自动调整降低最小量以达到1024的倍数
query_cache_type:控制 Query Cache 功能的开关,可以设置为0(OFF),1(ON)和2(DEMAND)三种,意义分别如下:
0(OFF):关闭 Query Cache 功能,任何情况下都不会使用 Query Cache
1(ON):开启 Query Cache 功能,但是当 SELECT 语句中使用的 SQL_NO_CACHE 提示后,将不使用Query Cache
2(DEMAND):开启 Query Cache 功能,但是只有当 SELECT 语句中使用了 SQL_CACHE 提示后,才使用 Query Cache
query_cache_wlock_invalidate:控制当有写锁定发生在表上的时刻是否先失效该表相关的 Query Cache,如果设置为 1(TRUE),则在写锁定的同时将失效该表相关的所有 Query Cache,如果设置为0(FALSE)则在锁定时刻仍然允许读取该表相关的 Query Cache。
Query Cache 如何处理子查询的?
这是我遇到的最为常见的一个问题。其实 Query Cache 是以客户端请求提交的 Query 为对象来处理的,只要客户端请求的是一个 Query,无论这个 Query 是一个简单的单表查询还是多表 Join,亦或者是带有子查询的复杂 SQL,都被当作成一个 Query,不会被分拆成多个 Query 来进行 Cache。所以,存在子查询的复杂 Query 也只会产生一个Cache对象,子查询不会产生单独的Cache内容。UNION[ALL] 类型的语句也同样如此。

Query Cache 是以 block 的方式存储的数据块吗?
不是,Query Cache 中缓存的内容仅仅只包含该 Query 所需要的结果数据,是结果集。当然,并不仅仅只是结果数据,还包含与该结果相关的其他信息,比如产生该 Cache 的客户端连接的字符集,数据的字符集,客户端连接的 Default Database等。

Query Cache 为什么效率会非常高,即使所有数据都可以 Cache 进内存的情况下,有些时候也不如使用 Query Cache 的效率高?
Query Cache 的查找,是在 MySQL 接受到客户端请求后在对 Query 进行权限验证之后,SQL 解析之前。也就是说,当 MySQL 接受到客户端的SQL后,仅仅只需要对其进行相应的权限验证后就会通过 Query Cache 来查找结果,甚至都不需要经过 Optimizer 模块进行执行计划的分析优化,更不许要发生任何存储引擎的交互,减少了大量的磁盘 IO 和 CPU 运算,所以效率非常高。

客户端提交的 SQL 语句大小写对 Query Cache 有影响吗?
有,由于 Query Cache 在内存中是以 HASH 结构来进行映射,HASH 算法基础就是组成 SQL 语句的字符,所以必须要整个 SQL 语句在字符级别完全一致,才能在 Query Cache 中命中,即使多一个空格也不行。

一个 SQL 语句在 Query Cache 中的内容,在什么情况下会失效?
为了保证 Query Cache 中的内容与是实际数据绝对一致,当表中的数据有任何变化,包括新增,修改,删除等,都会使所有引用到该表的 SQL 的 Query Cache 失效。

为什么我的系统在开启了 Query Cache 之后整体性能反而下降了?
当开启了 Query Cache 之后,尤其是当我们的 query_cache_type 参数设置为 1 以后,MySQL 会对每个 SELECT 语句都进行 Query Cache 查找,查找操作虽然比较简单,但仍然也是要消耗一些 CPU 运算资源的。而由于 Query Cache 的失效机制的特性,可能由于表上的数据变化比较频繁,大量的 Query Cache 频繁的被失效,所以 Query Cache 的命中率就可能比较低下。所以有些场景下,Query Cache 不仅不能提高效率,反而可能造成负面影响。

如何确认一个系统的 Query Cache 的运行是否健康,命中率如何,设置量是否足够?
MySQL 提供了一系列的 Global Status 来记录 Query Cache 的当前状态,具体如下:

Qcache_free_blocks:目前还处于空闲状态的 Query Cache 中内存 Block 数目
Qcache_free_memory:目前还处于空闲状态的 Query Cache 内存总量
Qcache_hits:Query Cache 命中次数
Qcache_inserts:向 Query Cache 中插入新的 Query Cache 的次数,也就是没有命中的次数
Qcache_lowmem_prunes:当 Query Cache 内存容量不够,需要从中删除老的 Query Cache 以给新的 Cache 对象使用的次数
Qcache_not_cached:没有被 Cache 的 SQL 数,包括无法被 Cache 的 SQL 以及由于 query_cache_type 设置的不会被 Cache 的 SQL
Qcache_queries_in_cache:目前在 Query Cache 中的 SQL 数量
Qcache_total_blocks:Query Cache 中总的 Block 数量
可以根据这几个状态计算出 Cache 命中率,计算出 Query Cache 大小设置是否足够,总的来说,我个人不建议将 Query Cache 的大小设置超过256MB,这也是业界比较常用的做法。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/491525.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
PHP框架开发人员视角:经验丰富的专业人士的见解
上一篇 2025年11月8日 15:56:40
win10系统如何去除任务栏中的地址栏?
下一篇 2025年11月8日 15:56:52

相关推荐

  • PHP自定义函数:创建与使用 prev_id() 函数的实践指南

    本文旨在指导读者如何定义和实现自定义PHP函数,以解决“Call to undefined function”错误。通过 prev_id() 函数的创建示例,详细阐述了函数的基本语法、参数传递、返回值以及在实际应用(如数据库查询)中的集成方法,并提供了关键注意事项,帮助开发者编写模块化、可维护的代码…

    2026年9月23日
    000
  • mysql数据库中触发器和存储过程如何协同

    触发器可调用存储过程实现复杂逻辑与数据一致性。例如,订单插入后通过触发器调用存储过程更新库存并记录日志;共用业务规则如积分调整封装在存储过程中,被多个触发器复用,提升可维护性;触发器还可调用存储过程插入异步任务到消息表,解耦耗时操作,由后台脚本处理通知或数据同步,保障主事务效率。 在MySQL数据库…

    2026年9月23日
    100
  • mysql索引怎么用 mysql创建索引提高查询性能方法

    mysql索引怎么用 mysql创建索引提高查询性能方法mysql索引怎么用 mysql创建索引提高查询性能方法mysql索引怎么用 mysql创建索引提高查询性能方法mysql索引怎么用 mysql创建索引提高查询性能方法

    索引是mysql中提高查询性能的关键工具,它类似于书籍目录,可快速定位数据。创建索引主要使用create index或alter table语句,例如:create index idx_email on users (email); 或 alter table users add index idx…

    2026年9月23日 用户投稿
    000
  • Windows系统安装MySQL的完整步骤是什么?

    Windows系统安装MySQL的完整步骤是什么?Windows系统安装MySQL的完整步骤是什么?Windows系统安装MySQL的完整步骤是什么?Windows系统安装MySQL的完整步骤是什么?

    安装#%#$#%@%@%$#%$#%#%#$%@_81c++3b080dad537de7e10e0987a4bf52e前需准备系统兼容性、硬件资源、前置运行时库、管理员权限及排查端口冲突。1. 系统兼容性:确保使用windows 10/11或对应server版本;2. 硬件资源:建议至少4gb内存;…

    2026年9月23日 用户投稿
    100
  • mysql怎么添加哈希索引 mysql创建哈希索引的使用场景

    mysql怎么添加哈希索引 mysql创建哈希索引的使用场景mysql怎么添加哈希索引 mysql创建哈希索引的使用场景mysql怎么添加哈希索引 mysql创建哈希索引的使用场景mysql怎么添加哈希索引 mysql创建哈希索引的使用场景

    mysql中可以显式添加哈希索引的场景仅限于memory存储引擎,1.创建memory表时通过using hash语法指定主键或辅助索引;2.对已有memory表使用alter table添加哈希索引。对于innodb等磁盘引擎,无法手动创建哈希索引,但其内部会自动管理自适应哈希索引(ahi)以优化…

    2026年9月23日 用户投稿
    100
  • Linux中如何查看服务日志?journalctl与syslog使用指南

    Linux中如何查看服务日志?journalctl与syslog使用指南Linux中如何查看服务日志?journalctl与syslog使用指南Linux中如何查看服务日志?journalctl与syslog使用指南Linux中如何查看服务日志?journalctl与syslog使用指南

    排查linux服务问题时,首选journalctl或syslog类系统查看日志。journalctl适用于systemd系统,可查看内核消息、服务启动输出等,支持按时间、单元、优先级过滤;syslog适用于传统系统,需服务主动发送日志,支持集中管理。掌握两者使用能有效定位问题。 在Linux系统中排…

    2026年9月23日 用户投稿
    100
  • mysql安装后怎么授权 mysql用户权限设置操作教程

    mysql安装后怎么授权 mysql用户权限设置操作教程mysql安装后怎么授权 mysql用户权限设置操作教程mysql安装后怎么授权 mysql用户权限设置操作教程mysql安装后怎么授权 mysql用户权限设置操作教程

    创建用户并授权需用create user和grant命令,常见权限包括select、insert、update、delete、create、drop和all privileges,修改权限可用grant或revoke,设置时应注意作用范围、远程访问限制和密码安全。1. 创建用户使用create us…

    2026年9月23日 用户投稿
    1000
  • 如何在mysql中配置用户连接权限

    创建用户并设置密码:使用CREATE USER指定主机和密码,如’localhost’或’%’(存在安全风险);2. 授予权限:通过GRANT赋予ALL、SELECT等操作权限,并用FLUSH PRIVILEGES生效;3. 验证管理:用SHOW GR…

    2026年9月23日
    900
  • mysql安装完如何优化 mysql基础性能调优配置建议

    mysql安装完如何优化 mysql基础性能调优配置建议mysql安装完如何优化 mysql基础性能调优配置建议mysql安装完如何优化 mysql基础性能调优配置建议mysql安装完如何优化 mysql基础性能调优配置建议

    安装完 mysql 后需进行基础配置调优以提升性能,主要包括以下五点:1. 设置 innodb_buffer_pool_size 为物理内存的50%~80%,如16g内存可设为12g;2. 调整 max_connections 至合理并发数如500,并设置 wait_timeout 和 intera…

    2026年9月23日 用户投稿
    400
  • mysql安装后怎么变量 mysql系统变量配置与修改

    mysql安装后怎么变量 mysql系统变量配置与修改mysql安装后怎么变量 mysql系统变量配置与修改mysql安装后怎么变量 mysql系统变量配置与修改mysql安装后怎么变量 mysql系统变量配置与修改

    要查看和修改mysql系统变量,可通过sql命令或配置文件操作。一、查看变量用show variables或查询information_schema.global_variables;二、常见需调整变量包括max_connections、innodb_buffer_pool_size、wait_ti…

    2026年9月23日 用户投稿
    600
  • 如何使用Optuna优化AI大模型训练?自动化调参的详细教程

    如何使用Optuna优化AI大模型训练?自动化调参的详细教程如何使用Optuna优化AI大模型训练?自动化调参的详细教程如何使用Optuna优化AI大模型训练?自动化调参的详细教程如何使用Optuna优化AI大模型训练?自动化调参的详细教程

    Optuna通过智能搜索与剪枝机制,显著提升AI大模型超参数优化效率。它以目标函数封装训练流程,利用TPE等算法智能采样,结合ASHA等剪枝策略,在分布式环境下高效搜索最优配置,同时提供可复现性与可视化分析,降低调参成本。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 Dee…

    2026年9月23日 用户投稿
    100
  • 如何在mysql中备份二进制日志

    答案:MySQL二进制日志备份可通过mysqlbinlog工具导出、直接复制日志文件、定时归档及结合mysqldump全量备份实现,需配合FLUSH LOGS和SHOW BINARY LOGS确保一致性,并制定保留策略以支持数据恢复。 在 MySQL 中,二进制日志(Binary Log)记录了所有…

    2026年9月23日
    100
  • 如何使用Java制作简易的博客系统

    首先搭建Spring Boot后端,设计BlogPost实体类并用JPA实现数据持久化,通过BlogController处理页面请求,使用Thymeleaf模板引擎渲染index和create页面,配置H2内存数据库并启用控制台,最终实现文章的发布与展示功能。 用Java制作一个简易的博客系统,核心…

    2026年9月23日
    200
  • mysql如何输入二进制数据 mysql代码处理blob类型教程

    mysql如何输入二进制数据 mysql代码处理blob类型教程mysql如何输入二进制数据 mysql代码处理blob类型教程mysql如何输入二进制数据 mysql代码处理blob类型教程mysql如何输入二进制数据 mysql代码处理blob类型教程

    mysql中存储二进制数据可通过选择合适的blob类型并使用sql命令实现。1. 选择tinyblob、blob、mediumblob或longblob之一,依据存储容量需求;2. 使用insert语句结合unhex()函数插入十六进制表示的二进制数据;3. 通过编程语言如php简化转换过程,使用b…

    2026年9月23日 用户投稿
    400
  • mysql如何输入特殊字符 mysql写sql语句的转义方法

    mysql如何输入特殊字符 mysql写sql语句的转义方法mysql如何输入特殊字符 mysql写sql语句的转义方法mysql如何输入特殊字符 mysql写sql语句的转义方法mysql如何输入特殊字符 mysql写sql语句的转义方法

    在mysql中处理特殊字符的核心方法是使用预处理语句,1.手动转义可通过反斜杠实现,如单引号转为’、双引号转为”等,但易出错且不安全;2.更推荐使用预处理语句(prepared statements)或参数绑定,它能自动处理特殊字符并防止sql注入;3.预处理语句的优势包括安全性高,彻底杜绝sql注…

    2026年9月23日 用户投稿
    400
  • Java中ConnectException连接异常的解决方法

    答案:Java中ConnectException通常因服务未启动、网络不通或配置错误导致,需检查服务状态、IP端口配置及防火墙设置,并合理设置连接超时与重试机制。 Java中出现ConnectException通常表示应用程序尝试连接到远程服务器时失败,最常见的原因是目标主机拒绝连接或网络不通。这个…

    2026年9月23日
    300
  • mysql怎么执行子查询 mysql输入嵌套sql语句方法

    mysql怎么执行子查询 mysql输入嵌套sql语句方法mysql怎么执行子查询 mysql输入嵌套sql语句方法mysql怎么执行子查询 mysql输入嵌套sql语句方法mysql怎么执行子查询 mysql输入嵌套sql语句方法

    mysql子查询常见类型包括标量子查询、行子查询和表子查询,分别返回一行一列、一行多列和多行多列数据;应用场景涵盖where作为过滤条件、from作为派生表、select作为标量列以及dml操作的数据提供。此外,根据与外部查询的关联性分为非关联子查询和关联子查询,前者独立执行一次,后者依赖外部查询每…

    2026年9月23日 用户投稿
    100
  • 深入理解 PHP PDO:正确获取最后插入ID的连接管理策略

    本文旨在解决 PHP PDO 中 lastInsertId() 方法返回 0 的常见问题。核心原因在于每次数据库操作时重复创建新的 PDO 连接,导致 lastInsertId() 无法在正确的会话中获取到自动递增ID。解决方案是优化数据库连接类,通过实现连接的单例模式,确保在整个请求生命周期内复用…

    2026年9月23日
    300
  • mysql如何分析索引使用 mysql创建索引后的执行计划解读

    mysql如何分析索引使用 mysql创建索引后的执行计划解读mysql如何分析索引使用 mysql创建索引后的执行计划解读mysql如何分析索引使用 mysql创建索引后的执行计划解读mysql如何分析索引使用 mysql创建索引后的执行计划解读

    要分析mysql索引使用和执行计划,核心是通过explain命令查看查询路径,并结合handler_read%状态变量评估索引效率。1. 使用explain命令分析执行计划,关注type、key、extra等列,判断是否高效利用索引;2. 通过show global status like &#82…

    2026年9月22日 用户投稿
    100
  • mysql怎么添加前缀索引 mysql创建前缀索引的长度选择

    mysql怎么添加前缀索引 mysql创建前缀索引的长度选择mysql怎么添加前缀索引 mysql创建前缀索引的长度选择mysql怎么添加前缀索引 mysql创建前缀索引的长度选择mysql怎么添加前缀索引 mysql创建前缀索引的长度选择

    在mysql中,为长字符串列添加前缀索引的核心目的是优化查询性能并节省存储空间。1. 前缀索引通过仅索引列值的前n个字符实现这一目标;2. 前缀长度的选择需在区分度与存储效率之间取得平衡,理想长度应确保高区分度(如90%以上)且不过度冗余;3. 可通过执行select count(distinct …

    2026年9月22日 用户投稿
    100

发表回复

登录后才能评论
关注微信