MySQL Reference Manual for version 4.1.0-alpha.


6.9 MySQL 查询缓存

从 MySQL 4.0.1 开始,MySQL server 有一个重要的特征:Query Cache。 当在使用中,查询缓存会存储一个 SELECT 查询的文本与被传送到客户端的相应结果。如果之后接收到一个同样的查询,服务器将从查询缓存中检索结果,而不是再次分析和执行这个同样的查询。

注意:查询缓存绝不返回过期数据。当数据被修改后,在查询缓存中的任何相关词条均被转储清除。

在某些表并不经常更改,而你又对它执行大量的相同查询时,查询缓存将是非常有用的。对于许多 WEB 服务器使用大量的动态信息,这是一个很典型的情况。

下面是查询缓存的一个性能数据。(这些结果的产生,是通过在一个 a Linux Alpha 2 x 500 MHz、2GB RAM 和 64MB 查询缓存上执行 MySQL 基准套件和到的):

6.9.1 查询缓存如何运作

查询在分析之前先被比较,因而

SELECT * FROM tbl_name

Select * from tbl_name

对于查询缓存被当作是不同的查询,因而查询需要严格的一致(字节对字节的),才会被认为是同样的。 另外,如果一个客户端使用一个新的连接协议格式或不同于其它客户端的另一个字符集,一个查询将被视为不同的。

使用不同数据库的,使用不同协议版本的,或使用不同的缺省字符串的查询将被认为是不同的查询,并将分别的缓冲。

高速缓冲不对 SELECT CALC_ROWS ...SELECT FOUND_ROWS() ... 类型的查询起作用,因为找到的行的数目也是被存储在缓冲里的。

如果查询结果被从查询缓存中返回,那么状态变量 Com_select 将不会被增加,但是 Qcache_hits 却会增加。查看章节 6.9.4 查询缓存的状态和维护

如果一个表发生的改变 (INSERT, UPDATE, DELETE, TRUNCATE, ALTERDROP TABLE|DATABASE),那么所有这张表使用的缓冲的查询(可能通过一个 MRG_MyISAM 表!)将被得失效,并从缓冲中移除。

InnoDB 表的事务所做的更改将在一个 COMMIT 被完成时,使数据失效。

如果一个查询包括下面的函数,它将不能被缓冲:
函数 函数 函数
User-Defined Functions CONNECTION_ID FOUND_ROWS
GET_LOCK RELEASE_LOCK LOAD_FILE
MASTER_POS_WAIT NOW SYSDATE
CURRENT_TIMESTAMP CURDATE CURRENT_DATE
CURTIME CURRENT_TIME DATABASE
ENCRYPT (只有一个参数调用) LAST_INSERT_ID RAND
UNIX_TIMESTAMP (无参数调用) USER BENCHMARK

如果一个查询包含用户变量,引用 MySQL 系统数据库,或下列之一的格式,SELECT ... IN SHARE MODE, SELECT ... INTO OUTFILE ..., SELECT ... INTO DUMPFILE ...SELECT * FROM AUTOINCREMENT_FIELD IS NULL (检索最后一个插入 ID - ODBC 语句),该查询亦不可以被缓存。

然而,FOUND ROWS() 将返回正确的值,即使先前的查询是从缓存中读取的。

万一一个查询不使用任何表,或使用临时表,或用户对任何相关表有一个列权限,那么查询将不会被缓存。

在一个查询从查询缓存中读取前,MySQL 将检查用户对所有相关的数据库和表有 SELECT 权限。如果不是这种情况,缓存的结果将不能被使用。

6.9.2 查询缓存设置

查询缓存为了 mysqld 添加了几个 MySQL 系统变量,它可以在配置文件中被设置,或在启动 mysqld 时的命令行上设置。

在一个线程(连接)内,查询缓存的行为可以被改变。句法如下所示:

QUERY_CACHE_TYPE = OFF | ON | DEMAND QUERY_CACHE_TYPE = 0 | 1 | 2

选项 含义
0 or OFF 不缓存或重新得到结果
1 or ON 缓存所有的结果,除了 SELECT SQL_NO_CACHE ... 查询
2 or DEMAND 仅缓存 SELECT SQL_CACHE ... 查询

6.9.3 在 SELECT 中的查询缓存选项

有两个可能的查询缓存相关的参数可以在一个 SELECT 查询中被指定:

选项 含义
SQL_CACHE 如果 QUERY_CACHE_TYPEDEMAND,允许该查询被缓存。如果 QUERY_CACHE_TYPEON,这是缺省的。如果 QUERY_CACHE_TYPEOFF,它不做任何事
SQL_NO_CACHE 使这个查询不被缓存,不允许这个查询被存储到高速缓存中

6.9.4 查询缓存的状态和维护

使用 FLUSH QUERY CACHE 命令,你可以整理查询缓存,以更好的利用它的内存。这个命令不会从缓存中移除任何查询。FLUSH TABLES 会转储清除查询缓存。

RESET QUERY CACHE 使命从查询缓存中移除所有的查询结果。

你可以检查查询缓存在你的 MySQL 是否被引进:

mysql> SHOW VARIABLES LIKE 'have_query_cache';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| have_query_cache | YES   |
+------------------+-------+
1 row in set (0.00 sec)

SHOW STATUS 中,你可以监视查询缓存的性能:

变量 含义
Qcache_queries_in_cache 在缓存中已注册的查询数目
Qcache_inserts 被加入到缓存中的查询数目
Qcache_hits 缓存采样数数目
Qcache_lowmem_prunes 因为缺少内存而被从缓存中删除的查询数目
Qcache_not_cached 没有被缓存的查询数目 (不能被缓存的,或由于 QUERY_CACHE_TYPE)
Qcache_free_memory 查询缓存的空闲内存总数
Qcache_free_blocks 查询缓存中的空闲内存块的数目
Qcache_total_blocks 查询缓存中的块的总数目

Total number of queries = Qcache_inserts + Qcache_hits + Qcache_not_cached.

查询缓存使用变长的块,因而 Qcache_total_blocksQcache_free_blocks 可能显示查询缓存的碎片。在 FLUSH QUERY CACHE 之后,只有剩余一个单独的(大的)空闲块。

注意:每个查询最小需要两个块(一个用于存储查询文本,另一个或多个用于存储查询结果)。同样的,每个被一个查询使用的表需要一个块,但是,如果有两个或更多的查询使用同一张表,仅仅只需要分配一个块就行了。

你可以使用状态变量 Qcache_lowmem_prunes 来谐调查询缓存尺寸。它计数被从缓存中移除的查询,该查询的移除是为了释放内存,以缓存新建的查询。查询缓存使用一个 least recently used (LRU) 策略来判断从缓存中移除哪个查询。