为了提高查询速度,MySQL 会维护一个内存区域(官方文档指出大小至少 41984 B)对查询结果进行缓存,当查询时发现缓存区里有数据则直接返回结果而不执行 SQL 语句。
查询命中的条件
- 每个缓存查询至少需要两个块(一个块用于查询文本,一个或多个块用于查询结果)。
- 每个查询使用的每个表需要一个块,如果两个或多个查询使用相同的表,仅需要分配一个块。
- 对于两个查询语句是否相同的判定,MySQL 比较严格,查询必须是完全相同的(逐字节相同)才能够被认为是相同的。
- 另外,同样的查询字符串由于其它原因可能认为是不同的,使用不同的数据库、不同的协议版本或者不同默认字符集的查询被认为是不同的查询并且分别进行缓存。例如,以下两个查询是不相同的:
SELECT * FROM ...
Select * from ...
缓冲区配置
MySQL 设置缓冲区大小命令:
set global query_cache_size=41984;
如果设置 query_cache_size
小于 41984,则设置失败并自动置 0。如果设为 0,则表示不使用缓冲区。当 query_cache_size
大于 0 ,并不能保证缓冲区会被使用,还必须根据变量 query_cache_type
来决定,该变量有三种状态,分别代表三种不同缓冲方式:
- 0 (或OFF),将阻止缓存或查询缓存结果;
- 1 (或ON),将允许缓存,以
SELECT SQL_NO_CACHE
开始的查询语句除外; - 2 (或DEMAND),仅对以
SELECT SQL_CACHE
开始的那些查询语句启用缓存。设置方式如下:
set session query_cache_type = OFF;
若报错,编辑配置文件 my.cnf
或 Windows下的 mysql/bin/my.ini
添加
[mysqld]
query_cache_size=256M
query_cache_type=1
重启 mysql 服务,查看是否设置成功:
show variables like "%query_cache%";
或执行
select @@query_cache_type;
查询结果的内存大小分配
- 要控制可以被缓存的具体查询结果的最大值,应设置
query_cache_limit
变量。默认值是1 MB
。 - 当一个查询结果(返回给客户端的数据)从查询缓冲中提取期间,它在查询缓存中排序。因此,数据通常不在大的数据块中处理。查询缓存根据数据排序要求分配数据块,因此,当一个数据块用完后分配一个新的数据块。因为内存分配操作是昂贵的(费时的),所以通过
query_cache_min_res_unit
系统变量给查询缓存分配最小值。当查询执行时,最新的结果数据块根据实际数据大小来确定,因此可以释放不使用的内存。根据你的服务器执行查询的类型,你会发现调整query_cache_min_res_unit
变量的值是有用的。query_cache_min_res_unit
默认值是4 KB
。这应该适合大部分情况。 - 如果你有大量返回小结果数据的查询,默认数据块大小可能会导致内存碎片,显示为大量空闲内存块。由于缺少内存,内存碎片会强制查询缓存从缓存内存中修整(删除)查询。这时,你应该减少
query_cache_min_res_unit
变量的值。空闲块和由于修整而移出的查询的数量通过Qcache_free_blocks
和Qcache_lowmem_prunes
变量的值给出。 - 如果大量查询返回大结果(检查
Qcache_total_blocks
和Qcache_queries_in_cache
状态变量),你可以通过增加query_cache_min_res_unit
变量的值来提高性能。但是,注意不要使它变得太大。 - 也就是说,则给查询结果分配缓冲区大小时,并不是再等待查询结果返回后根据结果大小来分配空间,而是先根据
query_cache_min_res_unit
分配一个内存,待结果返回后直接放入内存中。这时候分3种情况考虑: - 如果查询结果的大小 =
query_cache_min_res_unit
,则直接把结果存入到该缓冲区中。 - 如果查询结果的大小 <
query_cache_min_res_unit
,则直接把结果存入到该缓冲区中,然后把多分配的空间释放掉,这种情况容易产生内存碎片。 - 如果查询结果的大小 >
query_cache_min_res_unit
,则需要再分配内存空间来存放结果。
查询高速缓冲状态和维护
可以使用下面的语句检查MySQL服务器是否提供查询缓存功能:
show variables like 'have_query_cache';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| have_query_cache | YES |
+------------------+-------+
可以使用 FLUSH QUERY CACHE
语句来清理查询缓存碎片以提高内存使用性能。该语句不从缓存中移出任何查询。RESET QUERY CACHE
语句从查询缓存中移出所有查询。FLUSH TABLES
语句也执行同样的工作。为了监视查询缓存性能,使用 SHOW STATUS
查看缓存状态变量:
show status like 'Qcache%';
+-------------------------+--------+
|变量名 |值 |
+-------------------------+--------+
| Qcache_free_blocks | 36 |
| Qcache_free_memory | 138488 |
| Qcache_hits | 79570 |
| Qcache_inserts | 27087 |
| Qcache_lowmem_prunes | 3114 |
| Qcache_not_cached | 22989 |
| Qcache_queries_in_cache | 415 |
| Qcache_total_blocks | 912 |
+-------------------------+--------+
清除缓冲区释放空间
查询缓存使用长度可变块,因此 Qcache_total_blocks
和 Qcache_free_blocks
可以显示查询缓存内存碎片。执行 FLUSH QUERY CACHE
后,只保留一个空闲块。
flush query cache;