一、功能描述
子查询结果缓存的全局开关由系统变量 subquery_cache_enabled 控制,是否进入缓存还会受到代价阈值 subquery_cache_cost_threshold 的影响。即使 subquery_cache_enabled 为 OFF,只要 SQL 中显式指定了 CACHE_RESULT Hint,优化器仍会针对该子查询启用缓存。命中情况可通过状态变量 subquery_cache_hit 与 subquery_cache_miss 观察。
适用场景:
·关联子查询的关联列基数较低,外层查询多次以相同的关联键访问子查询。
·子查询本身的执行代价较高(聚合、复杂过滤等),且会被反复调用。
·全局未开启子查询结果缓存,仅希望对个别 SQL 临时启用。
二、语法
CACHE_RESULT 必须作为 SUBQUERY Hint 的策略参数出现,不能独立使用。
/*+ SUBQUERY([@query_block_name] CACHE_RESULT) */
参数说明:
·@query_block_name(可选):目标子查询所在查询块的名称。当省略时,Hint 内联在子查询的 SELECT 之后,作用于该子查询本身;当指定时,需要在目标子查询中通过 QB_NAME Hint 命名查询块。
两种典型写法:
·内联写法:将 Hint 直接写在子查询的 SELECT 关键字之后。
·命名查询块写法:在外层查询通过 @query_block_name 指定目标子查询。
三、相关变量
| 变量名 | 类型 | 默认值 | 作用域 | 说明 |
| subquery_cache_enabled | 系统变量 | OFF | Global、Session | 子查询结果缓存的全局开关。指定 CACHE_RESULT Hint 后,即使该开关为 OFF,对应子查询仍会启用缓存。 |
| subquery_cache_cost_threshold | 系统变量 | 4000 | Global、Session | 启用缓存的子查询代价阈值,仅当估算代价高于该阈值时进入缓存路径。 |
| subquery_cache_hit | 状态变量 | – | Global、Session | 子查询结果缓存命中次数。 |
| subquery_cache_miss | 状态变量 | – | Global、Session | 子查询结果缓存未命中次数。 |
四、示例
下例演示在全局关闭子查询结果缓存的情况下,使用 CACHE_RESULT Hint 对单条 SQL 启用缓存。
准备示例数据:
CREATE TABLE t1 (a INT, b INT, c VARCHAR(32));CREATE TABLE t2 (a INT, b INT);INSERT INTO t1 VALUES (1, 10, 'row1'), (2, 20, 'row2'), (3, 30, 'row3'), (4, 40, 'row4'), (5, 50, 'row5');INSERT INTO t2 VALUES (1, 100), (1, 110), (2, 200), (2, 210), (3, 300), (3, 310), (4, 400), (5, 500);ANALYZE TABLE t1, t2;SET subquery_cache_enabled = OFF;FLUSH STATUS;
示例 1:内联写法
EXPLAIN FORMAT=TREESELECT * FROM t1 WHERE b > (SELECT /*+ SUBQUERY(CACHE_RESULT) */ AVG(b) FROM t2 WHERE t2.a = t1.a);
执行计划中可观察到 Partial result cache on keys(t1.a),说明子查询已按关联列 t1.a 建立缓存。
示例 2:命名查询块写法
EXPLAIN FORMAT=TREESELECT /*+ SUBQUERY(@subq1 CACHE_RESULT) */ * FROM t1 WHERE b > (SELECT /*+ QB_NAME(subq1) */ AVG(b) FROM t2 WHERE t2.a = t1.a);
执行后,可通过状态变量观察缓存命中情况:
SHOW STATUS LIKE 'subquery_cache%';
返回结果示例:
Variable_name Valuesubquery_cache_hit <hit count>subquery_cache_miss <miss count>
注意:说明: