MySQL中间件之ProxySQL(9):ProxySQL的查询缓存功能

返回ProxySQL系列文章:http://www.cnblogs.com/f-ck-need-u/p/7586194.html

ProxySQL支持查询缓存的功能,可以将后端返回的结果集缓存在自己的内存中,在某查询的缓存条目被清理(例如过期)之前,前端再发起同样的查询语句,将直接从缓存中取数据并返回给前端。如此一来,ProxySQL处理的性能会大幅提升,也会大幅减轻后端MySQL Server的压力。

1.开启query cache功能

ProxySQL的查询缓存功能由mysql_query_rules表中的cache_ttl字段控制,该字段设置每个规则对应的缓存时长,时间单位为毫秒。

当前端发送的SQL语句命中了某规则后(严格地说,是最后应用的那条规则,因为链式规则下会操作多个规则),如果这个规则同时还设置了"cache_ttl"字段的值,则这个SQL语句返回的结果将会被缓存一定时间,过期后将等待专门的线程(purge线程)来清理。

例如:

delete from mysql_query_rules;
select * from stats_mysql_query_digest_reset where 1=0;

insert into mysql_query_rules(rule_id,active,apply,destination_hostgroup,match_pattern,cache_ttl)
values(1,1,1,10,"^select .* test1.t1",20000);

load mysql query rules to runtime;
save mysql query rules to disk;

select rule_id,destination_hostgroup,match_pattern,cache_ttl from mysql_query_rules;

这表示匹配上述规则(查询test1.t1表)的查询结果集将在ProxySQL上缓存20秒。

可以执行下面的语句进行测试,每个语句循环执行10次:

# 在bash下执行
proc="mysql -uroot [email protected]! -h127.0.0.1 -P6033 -e"
for ((i=0;i<10;i++));do
    $proc "select * from test1.t1;"
    $proc "select * from test1.t2;"
    $proc "select * from test2.t1;"
    $proc "select * from test2.t2;"
done

再去查看规则统计表:

Admin> select * from stats_mysql_query_rules;
+---------+------+
| rule_id | hits |
+---------+------+
| 1       | 10   |    <--rule_id=1的规则命中10次
+---------+------+

Admin> select hostgroup,count_star,sum_time,digest_text from stats_mysql_query_digest;
+-----------+------------+----------+------------------------+
| hostgroup | count_star | sum_time | digest_text            |
+-----------+------------+----------+------------------------+
| -1        | 9          | 0        | select * from test1.t1 | <-- 9次,hg="-1"
| 10        | 10         | 3640     | select * from test2.t1 |
| 10        | 10         | 3686     | select * from test2.t2 |
| 10        | 10         | 3986     | select * from test1.t2 |
| 10        | 1          | 1236     | select * from test1.t1 | <-- 1次,hg="10"
+-----------+------------+----------+------------------------+

其中,hostgroup=-1表示从缓存中取数据。

从上面的结果中,可以看出select * from test1.t1;语句除了被正常路由到后端执行的一次外,其它9次都是直接从缓存中获取数据的,且缓存取数据的语句执行总时间sum_time=0。

并不是所有的查询结果都应该缓存,ProxySQL的缓存空间毕竟有限。所以很有必要去stats_mysql_query_digest表中找出哪些语句应该缓存:执行次数多、总执行时间长、平均执行时间长的语句都应该缓存。这些指标也是合理判断读、写分离的指标。

2.查询缓存相关的统计数据

ProxySQL虽然实现了查询缓存功能,但是查询缓存设计的还不够完整,缺少一些锦上添花的功能,例如能查询到的缓存类指标比较少,控制缓存的方式也比较缺乏。不过作者一直在努力改进,不断完善。

以下是和查询缓存有关的状态变量:

Admin> SELECT * FROM stats_mysql_global WHERE Variable_Name LIKE '%Cache%';
+--------------------------+----------------+
| Variable_Name            | Variable_Value |
+--------------------------+----------------+
| Stmt_Cached              | 0              |
| Query_Cache_Memory_bytes | 0              |
| Query_Cache_count_GET    | 0              |
| Query_Cache_count_GET_OK | 0              |
| Query_Cache_count_SET    | 0              |
| Query_Cache_bytes_IN     | 0              |
| Query_Cache_bytes_OUT    | 0              |
| Query_Cache_Purged       | 0              |
| Query_Cache_Entries      | 0              |
+--------------------------+----------------+

各变量的意义如下:

  • Query_Cache_Memory_bytes:查询结果集已成功缓存在内存中的总大小,不包含那些元数据;
  • Query_Cache_count_GET:从查询缓存中取数据的请求总次数(GET requests);
  • Query_Cache_count_GET_OK:成功从缓存中GET到缓存的请求总次数(即命中缓存且缓存未过期);
  • Query_Cache_count_SET:缓存到查询缓存中的结果集总数(即有多少个查询的结果集进行了缓存);
  • Query_Cache_bytes_IN:写入到查询缓存的总数据量;
  • Query_Cache_bytes_OUT:从查询缓存中取出的总数据量;
  • Query_Cache_Purged:从缓存中移除(purged)的缓存结果集(缓存记录)数量;
  • Query_Cache_Entries:当前查询缓存中还有多少个缓存记录。

无法查询当前缓存空间中的具体的缓存记录信息。

3.ProxySQL查询缓存的细节

如下图:

ProxySQL通过变量mysql_query_cache_size_MB控制为查询缓存开辟多大的空间,通过变量mysql-threshold_resultset_size定义ProxySQL能缓存的单个最大结果集大小。

Admin> show  variables like '%size%';
+--------------------------------+-----------+
| Variable_name                  | Value     |
+--------------------------------+-----------+
| mysql-eventslog_filesize       | 104857600 |
| mysql-threshold_resultset_size | 4194304   |  <<<<
| mysql-query_cache_size_MB      | 256       |  <<<<
| mysql-stacksize                | 1048576   |
+--------------------------------+-----------+

ProxySQL通过SET调用将后端返回的结果集放进查询缓存空间,通过GET调用从查询缓存空间取出缓存数据返回给前端。当GET调用发现缓存记录已过期,会将其放进purge队列中。

purge线程会定时清理purge队列中的过期记录,还会定时扫描缓存空间以找出过期记录。当查询缓存空间已经满了(mysql-query_cache_size_MB),下一次SET调用也会触发purge线程来清理已经过期的缓存记录。所以,SET调用永远不会失败。但需要注意的是,如果已缓存内容占用的缓存空间低于3%,则purge线程不会清理任何内容,即使它们已经过期了。

缓存记录的数据结构如下:

key:value:length:expire_ms:access_ms:ref_count

其中:

  1. key/value分别是缓存的id和实际缓存的数据,key是根据username + schemaname + SQL statement做hash运算得到的值,这可以保证用户只会访问到它自己的、指定schema的结果集。
  2. length用于记录缓存记录的长度。因为mysql-threshold_resultset_size变量的原因,超出该变量阈值的那部分额外结果集不会放进缓存。
  3. expire_ms:用来记录每个缓存记录还有多长时间过期。
  4. access_ms:记录每个缓存记录最近一次被访问离现在已多久。
  5. ref_count:记录各缓存记录当前被引用数量。每次GET调用某缓存记录,该缓存记录的ref_count都会加1,调用完成后减1。这是为了避免正在调用的缓存记录正好过期又正好被purge线程发现而被清理。

所以,后面的3个字段都是为了让缓存记录过期而设计的。不过,目前ProxySQL还不支持根据access_ms来判断是否清理,例如缓存空间已满,且access_ms的时间已过去很久,但只要未过期,就不会被清理。这个字段可能是为以后的LRU(或其它类似缓存清理算法)做准备的。

4.容易误解的查询缓存

每个查询缓存记录的key是根据username + schemaname +SQL做hash运算出来的,这里的SQL是完整的包含参数SQL语句,而非参数化后的语句,如果SQL语句进行了重写,则使用重写后的完整的SQL语句参与hash运算。这很重要。

例如:

select * from tab where id between 10 and 20;
select * from tab where id between 10 and 19;
select * from tab where id=15;
select * from tab where id between 10 and 19;

第一个语句会缓存id=10到id=20之间的结果集,但第二个语句和第三个语句不会从这个缓存记录中取数据,而是从后端查询后设置自己的缓存记录,即使第二个语句参数化后的语句和第一个完全一样(它们是同一类语句,如下代码所示),所需要的数据也已经被第一个语句缓存。第四个语句会命中第二个语句的缓存。

select * from tab where id between ? and ?

但因为第二个语句和第一个语句命中的规则是同一个,所以这类语句的执行总次数会递增。

如下图:

原文地址:https://www.cnblogs.com/f-ck-need-u/p/9314459.html

时间: 2024-08-29 01:41:23

MySQL中间件之ProxySQL(9):ProxySQL的查询缓存功能的相关文章

MySQL的查询缓存功能现已成了瓶颈!

如果你在网上搜索一下"tuning MySQL query cache"(优化MySQL查询缓存),看到那么多的结果以及有人提供的五花八门的建议,这则新闻也就并不完全令人惊讶了. 正如MySQL Server的产品经理摩根·托克(Morgan Tocker)在这里撰写的那样,问题在于可扩展性. 缓存的操作看起来简单得很:SELECT(选择)命令存储在一个哈希表(又叫散列表,hash table)中:如果入站请求与哈希匹配,服务器就能返回上一次查询执行的结果(并且有保护机制,那样服务器不

MySql存储引擎+表解压缩机制+索引+查询缓存机制+慢查询日志

一.大型网站优化之MySql优化 1.优化和不优化的对比的 在业界当中我们有一个叫大数据(big data)的概念,所谓的大数据指代千万级别以上的数据作为起步的数据.所以我们现在需要对两张都具有50331650条记录的表进行查询对比,其中表名为tbl_no的表是没有做过任何优化手段的表,表名为tbl_yes的表是做过优化手段的表.这个实验的目的是观察具有优化手段和不具有优化手段的查询中速度的差别. 实验条件: 1)两张表的数据记录总数是相同的 2)两张表的数据字段结构也是一样的 3)查询的记录的

MySQL加速查询速度的独门武器:查询缓存

[导读] 与朋友或同事谈到MySQL查询缓存功能的时候,个人喜欢把查询缓存功能Query Cache比作荔枝, 是非常营养的东西,但是一次性吃太多了,就容易上火而流鼻血,虽然不是特别恰当的比喻,但是有很多相似的地方.另外Query Cache有其特殊的业务场景,MySQL也不像其他数据库产品,缓存查询语句的执行计划等信息,而是直接缓存查询语句的结果集和对应的SQL语句.本文 就给大家介绍下查询缓存的相关知识,希望可以引导大家正确地使用Query Cache独门武器. 对MySQL查询缓存从五个角

《高性能MySQL》读书笔记--查询缓存

1.MySQL查询缓存 很多数据库产品都能够缓存查询的执行计划,对于相同类型的SQL就可以跳过SQL解析和执行计划生成阶段.MySQL还有另一种不同的缓存类型:缓存完整的SELECT查询结果,也就是"查询缓存". 查询缓存系统会跟踪查询中涉及的每个表,如果这些表发生变化,那么和这个表相关的所有的缓存数据都将失效. 查询缓存对应用程序是完全透明的.应用程序无须关心MySQL是通过查询缓存返回的结果还是实际执行返回的结果. 另外,随着现在的通用服务器越来越强大,查询缓存可能是一个影响服务器

mysql基础(五)查询缓存

缓存的有缺点     1.如果命中缓存,直接从缓存中返回,减少分析和执行SQL语句的过程,提高查询效率     2.缓存会带来额外的开销,如果开启缓存的代价大于不开启缓存的代价则不建议开启缓存      缓存的开销     1.读查询在开始之前会先检查查询缓存     2.若某个读查询可以被缓存且未被缓存,那么当完成执行后,MySQL会将其结果存入查询缓存     3.对写操作也有影响,因为当写入数据时,MySQL必须将对应表的所有缓存都设置失效,     这在缓存内存较大时将导致很大的系统消耗

RDS for MySQL查询缓存 (Query Cache) 的设置和使用

https://help.aliyun.com/knowledge_detail/41717.html?spm=5176.7841698.2.11.aCvOXJ RDS for MySQL查询缓存 (Query Cache) 的设置和使用 功能和适用范围 原理 限制 设置 验证效果 1. 功能和适用范围 功能: 降低 CPU 使用率 降低 IOPS 使用率(某些情况下) 减少查询响应时间,提高系统的吞吐量 适用范围: 表数据修改不频繁.数据较静态 查询(Select)重复度高 查询结果集小于 1

数据库MySQL/mariadb知识点——查询缓存

查询的执行路径 SQL语句 查询缓存 解析器 解析树 预处理 查找最好的查询路径 查询优化SQL语句 执行计划 API调用存储引擎 调用数据,返回结果 缓存SELECT操作或预处理查询的结果集和SQL语句,当有新的SELECT语句或预处理查询语句请求,先去查询缓存,判断是否存在可用的记录集,判断标准:与缓存的SQL语句,是否完全一样,区分大小写. 不需要对SQL语句做任何解析和执行,当然语法解析必须通过在先,直接从Query Cache中获得查询结果,提高查询性能 查询缓存的判断规则,不够智能,

mysql查询缓存命中率

工作原理: 查询缓存的工作原理,基本上可以概括为: 缓存SELECT操作或预处理查询(注释:5.1.17开始支持)的结果集和SQL语句: 新的SELECT语句或预处理查询语句,先去查询缓存,判断是否存在可用的记录集,判断标准:与缓存的SQL语句,是否完全一样,区分大小写: 查询缓存对什么样的查询语句,无法缓存其记录集,大致有以下几类: 1. 查询语句中加了SQL_NO_CACHE参数: 2.查询语句中含有获得值的函数,包涵自定义函数,如:CURDATE().GET_LOCK().RAND().C

MySQL之变量、查询缓存和索引

MySQL中的系统数据库 mysql数据库:是mysql的核心数据库,类似于sql server中的master库,主要负责存储数据库的用户.权限设置.关键字等mysql自己需要使用的控制和管理信息 PERFORMANCE_SCHEMA:MySQL 5.5开始新增的数据库,主要用于收集数据库服务器性能参数,库里表的存储引擎均为PERFORMANCE_SCHEMA,用户不能创建存储引擎为PERFORMANCE_SCHEMA的表 information_schema数据库:MySQL 5.0之后产生