`

Mysql Query Cache学习篇

 
阅读更多

基础介绍篇:

QueryCache是用来缓存select语句结果集的一种机制,不是缓存execution plan。需要注意:对select语句的大小写空格敏感。

用张形象的图可以展现下(图是从网上“借”的):

无实验,无真像,我们还是动手理解下吧

先看下当前环境状态

mysql> select version();
+————–+
| version()    |
+————–+
| 5.1.45-debug |
+————–+
1 row in set (0.00 sec)

mysql> show status like ‘%qcache%’;
+————————-+———-+
| Variable_name           | Value    |
+————————-+———-+
| Qcache_free_blocks      | 1        |
| Qcache_free_memory      | 67099584 |
| Qcache_hits             | 0        |
| Qcache_inserts          | 0        |
| Qcache_lowmem_prunes    | 0        |
| Qcache_not_cached       | 2        |
| Qcache_queries_in_cache | 0        |
| Qcache_total_blocks     | 1        |
+————————-+———-+
8 rows in set (0.00 sec)

看看Query Cache的参数设置,已经打开query cache了(ON)

mysql> show variables like ‘%query_cache%’;
+——————————+———-+
| Variable_name                | Value    |
+——————————+———-+
| have_query_cache             | YES      |
| query_cache_limit            | 1048576  |
| query_cache_min_res_unit     | 2048     |
| query_cache_size             | 67108864 |
| query_cache_type             | ON       |
| query_cache_wlock_invalidate | OFF      |
+——————————+———-+
6 rows in set (0.00 sec)

这是一个有一百万行记录的测试表:

mysql> select count(distinct(pad)) from sbtest;
+———————-+
| count(distinct(pad)) |
+———————-+
|                    1 |
+———————-+
1 row in set (4.57 sec)

再看下状态,由于是第一次执行本select语句,自然没在cache中,所以是insert进去没hit到:
mysql> show status like ‘%qcache%’;
+————————-+———-+
| Variable_name           | Value    |
+————————-+———-+
| Qcache_free_blocks      | 1        |
| Qcache_free_memory      | 67098048 |
| Qcache_hits             | 0        |
| Qcache_inserts          | 1        |
| Qcache_lowmem_prunes    | 0        |
| Qcache_not_cached       | 2        |
| Qcache_queries_in_cache | 1        |
| Qcache_total_blocks     | 4        |
+————————-+———-+
8 rows in set (0.00 sec)

再执行一下同样的语句看看效果,执行时间真快呀
mysql> select count(distinct(pad)) from sbtest;
+———————-+
| count(distinct(pad)) |
+———————-+
|                    1 |
+———————-+
1 row in set (0.00 sec)

这下子hit到了^-^
mysql> show status like ‘%qcache%’;
+————————-+———-+
| Variable_name           | Value    |
+————————-+———-+
| Qcache_free_blocks      | 1        |
| Qcache_free_memory      | 67098048 |
| Qcache_hits             | 1        |
| Qcache_inserts          | 1        |
| Qcache_lowmem_prunes    | 0        |
| Qcache_not_cached       | 2        |
| Qcache_queries_in_cache | 1        |
| Qcache_total_blocks     | 4        |
+————————-+———-+
8 rows in set (0.00 sec)

如果语句大小写不一,还得insert没hit到,呵呵
mysql> select COUNT(distinct(pad)) from sbtest;
+———————-+
| COUNT(distinct(pad)) |
+———————-+
|                    1 |
+———————-+

1 row in set (1.99 sec)
mysql> show status like ‘%qcache%’;
+————————-+———-+
| Variable_name           | Value    |
+————————-+———-+
| Qcache_free_blocks      | 1        |
| Qcache_free_memory      | 67097024 |
| Qcache_hits             | 1        |
| Qcache_inserts          | 2        |
| Qcache_lowmem_prunes    | 0        |
| Qcache_not_cached       | 2        |
| Qcache_queries_in_cache | 2        |
| Qcache_total_blocks     | 6        |
+————————-+———-+
8 rows in set (0.00 sec)

如果sbtest表被update/insert/delete等语句操作后,这个select语句的query cache就会被失效。所以如果表被频繁更新,query cache的overhead就会被放大出来。一般的理论是默认打开QC,对一些涉及频繁更新的表的SQL语句可以加上SQL_NO_CACHE这样的sql hints来禁用query cache。

顺便提下官方文档里一个有意思的benchmark测试结果数据:

1. 从表中查出某一条特定记录这样的简单SQL,如果保证每个SQL不同,这样子没利用query cache机制,最终显示query cache的overhead是13%

2. 如果保证上述那些SQL一样,利用到了query cache机制的话,结果显示会加速238%

源码学习篇:

其实涉及的主要的数据结构就是个hash表,key是query + database + flag

这个flag很庞大的其实:

struct Query_cache_query_flags
{
unsigned int client_long_flag:1;
unsigned int client_protocol_41:1;
unsigned int result_in_binary_protocol:1;
unsigned int more_results_exists:1;
unsigned int in_trans:1;
unsigned int autocommit:1;
unsigned int pkt_nr;
uint character_set_client_num;
uint character_set_results_num;
uint collation_connection_num;
ha_rows limit;
Time_zone *time_zone;
ulong sql_mode;
ulong max_sort_length;
ulong group_concat_max_len;
ulong default_week_format;
ulong div_precision_increment;
MY_LOCALE *lc_time_names;
};

一个正常的select QUERY流程很长很长,可以从sql_parse.cc的dispatch_command开始看,当执行到里面的mysql_parse时我们就会看到里面开始涉及query cache了:

lex_start(thd);
mysql_reset_thd_for_next_command(thd);

if (query_cache_send_result_to_client(thd, (char*) inBuf, length) <= 0)

这个query_cache_send_result_to_client很关键,她会判断当前的QUERY能不能从cache中找到结果集,如果符合条件找到的话,就会略过parse_sql、mysql_execute_command也就是说不需要再经过LEX YACC等词语法解析了,也不需要经过语句执行时和存储引擎打交道,避免掉操作系统层和disk之间的IO了。如果找不到,就会解析执行,并且如果结果集小于query_cache_limit参数值时会放到cache中(具体详见Query_cache::store_query函数)

那个hash查找是这样:

query_block = (Query_cache_block *)  hash_search(&queries, (uchar*) sql,
tot_length);
至于具体的与query_cache_min_res_unit参数关联很大的cache内存分配策略、update/insert/delete时invalidate cache等等,我们都可以通过单步debug来学习,这里就不一一详述了:)

分享到:
评论

相关推荐

    Mycat处理连接数据库8.0以上程序报错query_cache_size

    然而,当Mycat与MySQL 8.0及以上版本配合使用时,可能会遇到一些兼容性问题,其中“query_cache_size”报错就是典型的例子。 在MySQL 8.0中,查询缓存功能被默认禁用,并且在某些版本中被完全移除。这是由于MySQL...

    解决mycatJDBC8驱动连接Mycat1.6报错 Unknown system variable 'query_cache_size'

    这个问题出现的原因在于MySQL 8.0版本中移除了`query_cache`相关的系统变量和功能,因此在使用新版本的JDBC驱动去连接旧版Mycat(可能基于较早版本的MySQL)时,会因找不到这个变量而抛出错误。 首先,我们需要理解...

    对于mysql的query_cache认识的误区

    如果空格是加在query之前,比如是在query的起始处加了空格,这样是丝毫不影响query cache的结果的,mysql认为这是一条query, 而如果空格是在query中,那会影响query cache的结果,mysql会认为是不同的query

    MySQL高速缓存启动方法及参数详解(query_cache_size)

    会发现其变量have_query_cache的值是yes,MYSQL初学者很容易以为这个参数为YES就代表开启了查询缓存,实际上是不对的,该参数表示当前版本的MYSQL是否支持Query Cache,实际上是否开启查询缓存是看另外一个参数的值:...

    MySQL的Query Cache原理分析

    MySQL的Query Cache是一种用于优化数据库性能的机制,它主要针对`SELECT`查询,旨在减少对磁盘I/O的依赖,通过缓存查询结果来提高数据检索速度。在MySQL中,Query Cache的工作原理基于SQL语句的精确匹配。当一个`...

    MSQL问题集合,线上环境到底要不要开启query cache

    MSQL 问题集合,线上环境到底要不要开启 query cache MSQL 问题集合中关于 Query Cache(查询缓存)的讨论非常重要。在线上环境中,到底要不要开启 query cache 是一个需要仔细考虑的问题。 Query Cache 的优点是...

    MySQL查询加速器:利用Query Cache提升效率

    - **易于使用**:MySQL提供了简单直观的界面和丰富的文档,便于用户学习和使用。 - **可扩展性**:MySQL支持从小型应用到大型企业级应用的扩展。 - **社区支持**:由于其广泛的使用,MySQL拥有一个活跃的开发者社区...

    mysql参数及其优化

    query_cache_size、query_cache_type、innodb_buffer_pool_size、innodb_log_file_size、innodb_log_buffer_size、innodb_flush_logs_at_trx_commit、transaction_isolation、innodb_file_per_table、innodb_open_...

    MySQL取消了Query Cache的原因

    MySQL之前有一个查询缓存Query Cache,从8.0开始,不再使用这个查询缓存,那么放弃它的原因是什么呢?在这一篇里将为您介绍。 MySQL查询缓存是查询结果缓存。它将以SEL开头的查询与哈希表进行比较,如果匹配,则返回...

    Mysql Mysql学习资料

    - 缓存机制:使用查询缓存(Query Cache)和InnoDB Buffer Pool提升性能。 4. **MySQL安全** - 用户权限管理:创建用户、设置密码策略,以及GRANT和REVOKE命令的使用。 - 权限控制:理解不同级别的权限(如...

    mysql题库完整版

    - **解释:** 在高并发环境下,尽管Query Cache的命中率很高,但由于请求的数量增加,导致更多的查询需要被缓存或替换现有的缓存项。这会增加Query Cache的管理开销,从而影响性能。因此,随着并发用户的增加,Query...

    超经典mysql dba 学习笔记.zip

    监控MySQL的状态是DBA日常工作的部分,这涉及了如何使用MySQL自带的性能_schema,以及第三方工具如Percona Toolkit、pt-query-digest等。当遇到性能问题或异常时,如何进行故障排查和诊断。 八、高级特性 MySQL的...

    mysql常用配置参数和状态变量

    7. Query_cache_limit:Query Cache 存放的单条 Query 最大 Result set(结果集),默认 1MB。 8. Qcache_free_memory:Query Cache 中目前剩余的内存大小。通过这个参数可以较为准确的观察出当前系统中的 Query ...

    memcached面试专题及答案.pdf

    MySQL 的 query cache 是集中式的,连接到该 query cache 的 MySQL 服务器都会受益。而 Memcached 则是一个分布式的缓存系统,可以水平扩展以满足大规模系统的需求。 Memcached 相比 MySQL 的 query cache,有以下...

Global site tag (gtag.js) - Google Analytics