mysql query cache

本文探讨了MySQL中查询缓存在事务内的工作原理及其与空白和注释的关系。实验结果显示,一旦事务内修改了表,则直到该事务提交前,涉及该表的所有查询都无法使用查询缓存。此外,文章还讨论了空白字符和注释如何影响查询缓存的命中率。

1. works with Transactions

http://www.mysqlperformanceblog.com/2008/01/29/how-mysql-query-cache-works-with-transactions/ 写道
The result set can be retrieved from query cache (for statements both inside and outside of transactions) until there is a statement inside transactions which modifies the table. As soon as table is modified in transaction it becomes uncachable by query cache until that transaction is committed. Not only query cache can’t be used inside the same transaction which modified data but also in other concurrent transactions which do not even see the changes done yet.
With current approach Innodb can probably do something as simple as marking table “uncachable ” if it has any uncommitted changed which would take care about all complicated aspects of change visibility in different transaction modes.

 

transaction 1 :
start transaction;
select count(*) from parent;  //  result: 1   QCache_hits : 0
select count(*) from parent;  //  result: 1   QCache_hits : 1

transaction 2 :
start transaction;
select count(*) from parent;  //  result: 1   QCache_hits : 2
insert into parent(name) values('new');
select count(*) from parent;  //  result: 2   QCache_hits : 2

transaction 1 :
select count(*) from parent;  //  result: 1   QCache_hits : 2




transaction 2 :
commit;

transaction 1 :
select count(*) from parent;  //  result: 1   QCache_hits : 2

commit;
select count(*) from parent;  //  result: 2   QCache_hits : 2



select count(*) from parent;  //  result: 2   QCache_hits : 3

transaction 2 :
select count(*) from parent;  //  result: 2   QCache_hits : 4
 

 the experiment result perfectly explains  the mechanism of mysql cache query with transactions.

 

 

2. WhiteSpace and comments

http://www.mysqlperformanceblog.com/2008/03/20/mysql-query-cache-whitespace-and-comments/ 写道
You can have whitespace in the start and you can have leading comment and it all works. However the comment which is inside the query works interesting way - the queries with different comments are both treated as same query if only comment is different. However if you change whitespace a bit (see the last query has space after comment deleted) it causes query cache miss.
Whitespace at the start of query does not block query from being cached . Moreover query with 2 spaces in front is considered same as query with 3 spaces in front
Comment at the start of the query does not block query from being cached. However queries with different comments are considered different queries (it is not stripped before hashing) - so you should not put things like current time in such a comment.
Comments inside the query also matter. Meaning if you place comments inside the query or in the end. Though this was always the case
 
select count(*) from parent;  //  QCache_hits : 0
select count(*) from parent;  //  QCache_hits : 1
/*comment*/ select count(*) from parent;  //  QCache_hits : 2             //  whitespace and comment at the start of query 
/*newcomment*/ select count(*) from parent;  //  QCache_hits : 3      //   does not block query from
/*comment*/select count(*) from parent;  //  QCache_hits : 4              //   being cached.

select /*comment*/ count(*) from parent;  //  QCache_hits : 4             // comments inside
select /*new comment*/ count(*) from parent;  //  QCache_hits : 5

select /*comment*/count(*) from parent;  //  QCache_hits : 5         // no whitespace between count(*) and comments.
select /*newcomment*/count(*) from parent;  //  QCache_hits : 6

select /*comment*/   count(*) from parent;  //  QCache_hits : 6      // one more whitespace before count(*)
 

 

<think>我们正在讨论MySQL的查询计划缓存(Query Plan Cache)。根据用户的问题,我们需要提供Query Plan Cache的定义和相关信息。需要注意的是,MySQL中并没有一个名为“Query Plan Cache”的独立缓存,但通常我们提到的查询缓存(Query Cache)和准备语句的缓存(Prepared Statement Cache)与查询计划相关。 然而,在MySQL中,查询缓存(Query Cache)缓存的是整个SELECT查询的结果集,而不是查询计划本身。而对于查询计划缓存,实际上在MySQL 8.0之前,存储过程有查询计划缓存,但对于一般的SQL语句,MySQL并不会缓存查询计划(除了准备语句)。 在MySQL 8.0中,引入了执行计划缓存(Execution Plan Cache)用于准备好的语句(prepared statements)。所以,用户可能指的是这个。 因此,我们将重点介绍MySQL中的执行计划缓存(用于准备语句)以及可能相关的查询缓存(但注意,查询缓存已在MySQL 8.0中被移除)。 由于用户的问题是关于“Query Plan Cache”,我们主要讨论执行计划缓存(针对准备语句)。 定义: 执行计划缓存(Execution Plan Cache)是MySQL中用于存储预处理语句(prepared statements)的执行计划的一种缓存机制。当相同的预处理语句再次执行时,MySQL可以重用之前编译好的执行计划,从而跳过优化和编译阶段,提高执行效率。 详细介绍: 1. 缓存对象:执行计划缓存针对的是预处理语句(Prepared Statements)。预处理语句是通过`PREPARE ... FROM`创建的,或者通过客户端驱动程序(如Connector/J、Connector/Python等)以二进制协议发送的语句(通常使用参数化查询)。 2. 工作原理: - 当预处理语句第一次执行时,MySQL会进行解析、优化,并生成执行计划,然后将执行计划缓存起来。 - 后续执行相同的预处理语句时,MySQL会直接使用缓存的执行计划,只需将参数替换即可执行,从而节省了优化时间。 3. 缓存管理: - 缓存大小由系统变量`cached_prepared_statements`控制(在MySQL 5.7中,这个变量是`max_prepared_stmt_count`,但在MySQL 8.0中,执行计划缓存的管理有所变化)。 - 在MySQL 8.0中,执行计划缓存的大小由系统变量`prepared_statement_cache_size`(会话级别)和`prepared_statement_cache_size_limit`(全局限制)控制。 - 缓存采用LRU(最近最少使用)策略进行管理。 4. 注意事项: - 执行计划缓存只对预处理语句有效,普通的查询语句不会缓存执行计划。 - 当表结构发生变化(如ALTER TABLE)或数据分布发生显著变化(导致统计信息更新)时,相关的执行计划会被自动从缓存中移除,以确保执行计划的正确性。 - 执行计划缓存是会话级别的,但全局参数可以限制总的缓存大小。 5. 与查询缓存的区别: - 查询缓存(Query Cache)缓存的是查询结果集,而执行计划缓存缓存的是执行计划(即如何执行查询的步骤)。 - 查询缓存在MySQL 8.0中被移除,而执行计划缓存仍然存在。 6. 相关系统变量(以MySQL 8.0为例): - `prepared_statement_cache_size`: 每个会话缓存的预处理语句数量(默认值根据文档可能有所不同,通常为256)。 - `prepared_statement_cache_size_limit`: 全局限制,防止所有会话的总缓存占用过多内存(默认值通常为2MB,但实际存储的是计划,不是结果)。 7. 监控: - 可以通过`SHOW STATUS LIKE 'Com_prepare_sql'`和`SHOW STATUS LIKE 'Com_execute_sql'`来查看预处理语句的准备工作次数和执行次数。 - 状态变量`Prepared_stmt_count`显示当前系统中的预处理语句数量(包括缓存的)。 需要注意的是,在MySQL 5.7及之前,执行计划缓存的行为和配置有所不同。 由于用户引用的内容中提到了EXPLAIN和SHOW PROCESSLIST等,这些虽然与查询计划有关,但不是直接针对执行计划缓存的。因此,我们主要围绕上述内容回答。 根据引用[1]中的内容,EXPLAIN只能解释SELECT操作,而且部分统计信息是估算的,这也说明了为什么执行计划缓存很重要,因为重复的预处理语句可以避免重复优化。 现在,我们将回答组织如下: </think>### MySQL 查询计划缓存(Query Plan Cache)的定义与介绍 #### 定义 MySQL **查询计划缓存**(Query Plan Cache)是一种优化机制,用于存储已解析和优化后的SQL语句执行计划。当相同的SQL语句重复执行时,MySQL可直接重用缓存的执行计划,**跳过语法解析、语义检查和优化器计算等步骤**,从而显著提升查询性能。该缓存主要针对**预处理语句(Prepared Statements)**。 #### 核心特性 1. **缓存对象** - 仅缓存预处理语句(通过`PREPARE`创建或应用程序参数化查询)的优化执行计划。 - 普通即时查询(Ad-hoc Query)**不缓存**执行计划。 2. **缓存生命周期** - 会话级缓存:默认绑定到客户端会话,会话结束时自动释放。 - 全局管理:通过参数控制全局缓存总量(如`prepared_statement_cache_size`)。 3. **缓存失效机制** 当以下操作发生时,相关执行计划自动失效: - 表结构变更(`ALTER TABLE`) - 索引添加/删除 - 统计信息更新(如`ANALYZE TABLE`) - 数据量剧烈变化(导致优化器重新选择索引)[^1] 4. **性能提升原理** ![执行计划缓存对比](https://www.mysqltutorial.org/wp-content/uploads/2018/11/MySQL-Prepared-Statement-Execution-Plan-Cache.png) 首次执行需完整流程(解析→优化→执行),后续执行**直接跳至执行阶段**。 #### 相关配置参数 | 参数名 | 作用 | 默认值 | |---------------------------------|----------------------------------------------------------------------|---------------| | `prepared_statement_cache_size` | 单个会话最大缓存的预处理语句数量 | 256(条) | | `performance_schema_max_prepared` | 监控缓存的性能模式指标数量 | 动态调整 | | `max_prepared_stmt_count` | 全局最大预处理语句数量(含缓存和活跃语句) | 16,382 | #### 局限性 1. **不适用于即时查询** 如`SELECT * FROM users WHERE id=1;`这类非参数化查询无法利用缓存[^1]。 2. **内存开销** 每个缓存的执行计划约占用10-100KB内存,需权衡性能与资源消耗。 3. **动态环境适应性差** 数据分布频繁变化时,缓存可能保留非最优计划,需手动清除(`DEALLOCATE PREPARE`)[^1]。 #### 操作示例 ```sql -- 创建预处理语句(自动缓存执行计划) PREPARE user_query FROM 'SELECT * FROM users WHERE age > ?'; -- 首次执行(解析+优化+执行) SET @age_threshold = 30; EXECUTE user_query USING @age_threshold; -- 后续执行(直接使用缓存计划) SET @age_threshold = 40; EXECUTE user_query USING @age_threshold; -- 手动释放缓存 DEALLOCATE PREPARE user_query; ``` #### 监控方法 ```sql -- 查看缓存命中率(Com_stmt_execute vs Com_stmt_prepare) SHOW GLOBAL STATUS LIKE 'Com_stmt%'; ``` - **高缓存命中率标志**:`Com_stmt_execute` >> `Com_stmt_prepare` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值