查询缓存原理

Query Cache是MySQL中的一个缓存机制,可以缓存SELECT语句的查询结果,提高查询性能。当再次执行相同的查询语句时,MySQL会尝试从缓存中获取结果,而不必重新执行查询语句。

Query Cache的工作流程如下:

1、当一个SELECT语句执行时,MySQL会先检查查询缓存,是否有该查询的结果。

2、如果缓存中有该查询的结果,则直接返回结果给客户端。

3、如果缓存中没有该查询的结果,则执行查询语句,将结果存储到缓存中,并返回结果给客户端。

可以使用以下语句查看Query Cache的状态:

SHOW VARIABLES LIKE 'query_cache_%';

Query Cache的状态可以通过修改以下系统变量进行配置:

query_cache_type:决定Query Cache的开启和关闭,默认为ON。
query_cache_size:决定Query Cache的大小,以字节为单位,默认为0,表示不限制大小。
query_cache_limit:决定Query Cache中单个结果集的大小限制,以字节为单位,默认为1MB。

注:1、Query Cache只适用于对静态数据的查询,并且可能会因为查询结果集的不断更新而失效。因此,在高并发、动态更新频繁的应用场景中,建议关闭Query Cache;

      2、缓存SELECT操作或预处理查询的结果集和SQL语句,当有新的SELECT语句或预处理查询语句请求,先去查询缓存,判断是否存在可用的记录集,判断标准:与缓存的SQL语句,是否完全一样,区分大小写。

哪些语句不能使用缓存

使用了用户自定义函数
使用了非确定性函数,例如 NOW() 和 UUID()
使用了系统变量,例如 @@GLOBAL.server_uuid 和 @@SESSION.sql_mode
语句中包含了用户变量或者全局变量
查询中使用了临时表
查询中使用了不支持缓存的存储引擎,例如 BLOB 和 TEXT 类型的列
查询中使用了 LOCK TABLES 和 UNLOCK TABLES 语句
查询中使用了多表更新和删除操作
查询语句中加了SQL_NO_CACHE参数
某用户只有列级别权限的查询语句
事务隔离级别为Serializable时,所有查询语句都不能缓存
查询缓存相关的服务器变量

query_cache_type:指定查询缓存使用的类型,可以是 ON、OFF 或 DEMAND。ON 表示缓存所有 SELECT 语句(默认值),OFF 表示不使用缓存,DEMAND 表示只有当语句中包含 SQL_CACHE 关键字时才使用缓存。

query_cache_size:指定查询缓存可用的内存大小,以字节为单位。

query_cache_limit:指定单个查询结果可以缓存的最大值,以字节为单位。

query_cache_min_res_unit:指定每个查询结果块的最小大小,以字节为单位。

query_cache_strip_comments:指定是否从查询语句中删除注释,以便更好地利用查询缓存。

query_cache_wlock_invalidate:指定在查询缓存中缓存表时是否自动失效其他客户端的写锁。

query_cache_mutexes:指定查询缓存使用的互斥锁数目。

这些变量可以通过 SET 命令修改,也可以通过在 my.cnf 文件中设置来永久更改。

13、MySQL-查询缓存Query Cache _查询缓存

SELECT语句的缓存控制

SELECT语句的缓存控制可以通过在SQL语句中使用SQL_CACHE和SQL_NO_CACHE来实现。

使用SQL_CACHE来显式指定SELECT语句使用缓存,例如:

SELECT SQL_CACHE * FROM users WHERE id = 1;

使用SQL_NO_CACHE来显式指定SELECT语句不使用缓存,例如:

SELECT SQL_NO_CACHE * FROM users WHERE id = 1;

需要注意的是,如果查询语句中包含非确定性的函数(例如NOW()、UUID()等)或用户变量,即使使用了SQL_CACHE,也不会被缓存。因此,在使用查询缓存时,应该尽量避免使用这些函数和变量。

此外,查询缓存的开销也比较大,因此在高并发的情况下,应该谨慎使用查询缓存

查询缓存状态变量

MySQL 8.0 版本已经弃用查询缓存,因此在该版本中无法查询和配置与查询缓存相关的状态变量。但是,在 MySQL 5.7 及更早版本中,可以使用以下命令查询与查询缓存相关的状态变量:

Qcache_free_blocks:查询缓存中空闲块的数量。

Qcache_free_memory:查询缓存中可用于存储查询结果的空闲内存量,以字节为单位。

Qcache_hits:从查询缓存中获取结果的次数。

Qcache_inserts:将查询结果存储到查询缓存中的次数,未命中次数。

Qcache_lowmem_prunes:由于内存压力而从查询缓存中删除结果的次数。

Qcache_not_cached:由于查询语句不符合查询缓存规则而未被缓存的查询数量。

Qcache_queries_in_cache:当前存储在查询缓存中的查询数量。

Qcache_total_blocks:查询缓存中块的总数量。

可以使用以下命令查询这些状态变量的值:

SHOW GLOBAL STATUS LIKE 'Qcache%';

需要注意的是,在使用查询缓存时,需要在 MySQL 配置中启用它,可以设置query_cache_type变量的值为 DEMAND、ON 或 OFF,以决定查询缓存是否启用,如下所示:

SET GLOBAL query_cache_type = ON;

也可以在 MySQL 配置文件 my.cnf 中设置 query_cache_type 来进行持久化配置。

13、MySQL-查询缓存Query Cache _查询缓存_02

13、MySQL-查询缓存Query Cache _query cache_03

命中率和内存使用率估算

查询缓存中内存块的最小分配单位query_cache_min_res_unit :

(query_cache_size - Qcache_free_memory) / Qcache_queries_in_cache

查询缓存命中率

命中率 = (Qcache_hits / (Qcache_hits + Qcache_inserts)) * 100%。

查询缓存内存使用率

内存使用率指的是查询缓存使用的内存占所有可用内存的比例,其计算公式为:内存使用率 = (query_cache_size – qcache_free_memory) / query_cache_size * 100%
查询缓存优化
以下是 MySQL 查询缓存优化的流程:
1、检查查询缓存是否开启
2、如果开启了查询缓存,检查当前查询是否在缓存中
3、如果当前查询在缓存中,直接从缓存中返回结果
4、如果当前查询不在缓存中,执行查询并将结果缓存起来
5、检查缓存是否达到了缓存大小限制,如果达到了限制,清空缓存
6、定期检查缓存中的数据是否过期,如果过期,从缓存中删除
7、不适合缓存的查询不应该缓存,例如包含随机数或时间戳的查询
8、避免在写操作后立即进行读操作,这会使缓存失效
9、避免在频繁更新的表上使用查询缓存,这会导致缓存频繁失效
10、对于需要进行排序或分组的查询,不适合使用查询缓存
以上是 MySQL 查询缓存优化的流程图,注意需要根据实际情况调整和优化。

MySQL查询缓存虽然可以提高查询速度,但在高并发环境下使用也会带来一些问题,比如查询缓存锁等待、缓存清除导致CPU负载高等。以下是一些查询缓存优化的建议:

1、设置合适的缓存大小

查询缓存的大小决定了它可以缓存多少查询结果,过大会占用过多的内存,过小则无法缓存足够多的查询结果。可以使用query_cache_size变量来调整缓存大小,建议将其设置为总内存的10%左右。

2、限制缓存可用范围

查询缓存是基于查询语句的,如果查询中含有变量或者当前时间等动态因素,则无法缓存。可以使用query_cache_type变量将其设置为DEMAND模式,只有显式启用缓存的查询才会被缓存。

3、避免使用不必要的大查询

查询缓存只有在查询结果完全匹配时才能被使用,因此如果查询结果集很大,则缓存的效率会很低。可以尽量避免返回过大的结果集,或者使用分页查询等方式降低结果集大小。

4、使用缓存提高重复查询性能

如果某个查询会被重复执行,可以使用SQL_CACHE关键字强制使用查询缓存,提高查询性能。但是需要注意,如果查询结果很少被重复使用,则这种方式会占用不必要的缓存空间。

5、调整锁等待超时时间

当查询缓存锁被占用时,查询请求会等待锁释放。可以使用query_cache_lock_wait_timeout变量来调整等待超时时间,减少等待时间对系统性能的影响。但是需要注意,等待时间过短会导致缓存的重复利用率降低。

6、监控缓存状态

可以通过SHOW STATUS命令来查看查询缓存的状态变量,比如缓存命中率、缓存大小和已用缓存量等。通过监控这些状态变量,可以及时调整缓存大小和使用策略,保证系统性能的稳定和可靠。