Query optimization can take longer than execution itself for certain SQL patterns. When the same query runs repeatedly, re-optimizing each time adds unnecessary overhead. Auto Plan Cache stores execution plans and reuses them for matching queries, reducing optimization time and improving throughput.
Enable the feature by setting the loose_plan_cache_type parameter to AUTO, DEMAND, or ENFORCE based on your workload.
How it works
The query optimizer selects an execution plan based on statistics, join orders, and query transformations. For queries where optimization time is a significant fraction of total execution time, caching the plan eliminates repeated optimizer work for the same query pattern.
Auto Plan Cache intercepts queries that match configured thresholds and stores their execution plans. Subsequent queries matching the same parameterized pattern use the cached plan directly, skipping the optimization phase.
Cached plans are automatically invalidated when:
Statistics on referenced tables change
DDL operations are performed on referenced tables
Not all queries benefit from plan caching. For queries where the optimal plan depends heavily on parameter values—where different values lead to very different optimal plans—a fixed cached plan may degrade performance. Use AUTO mode to cache selectively, or DEMAND mode to control which queries are cached.
Supported versions
Auto Plan Cache requires one of the following:
PolarDB for MySQL 8.0.1, revision version 8.0.1.1.33 or later
PolarDB for MySQL 8.0.2, revision version 8.0.2.2.12 or later
Choose a caching mode
Set the mode using the loose_plan_cache_type parameter.
| Mode | When to use |
|---|---|
| AUTO | Cache execution plans automatically for queries that meet the time and ratio thresholds. Best for production workloads where you want selective caching without manual query management. |
| DEMAND | Cache only the queries you explicitly register using the dbms_sql.add_plan_cache stored procedure. Best when you know exactly which queries need caching. |
| ENFORCE | Cache execution plans for all queries. Use only for testing or when all queries are known to benefit from caching. |
OFF (default) disables plan caching entirely.
Configure parameters
Configure the following parameters on the Parameters page of the PolarDB console. For more information, see Configure cluster and node parameters.
| Parameter | Description | Default |
|---|---|---|
loose_plan_cache_type | The caching mode: OFF, AUTO, DEMAND, or ENFORCE. | OFF |
loose_plan_cache_expire_time | How long (in seconds) to retain a cached plan that has not been matched. Valid values: 0–4294967295. | 1800 |
loose_auto_plan_cache_pct_threshold | The minimum ratio (as a percentage) of optimization time to total execution time required to cache a plan in AUTO mode. Valid values: 0–100. | 20 |
loose_auto_plan_cache_time_threshold | The minimum total execution time (in microseconds) required to cache a plan in AUTO mode. Valid values: 0–18446744073709551615. | 400 |
loose_auto_plan_cache_count_threshold | The minimum number of executions required before the cached plan takes effect in AUTO mode. Valid values: 0–18446744073709551615. | 512 |
AUTO mode cache conditions
A query's execution plan is cached only when both conditions are met:
Total execution time >=
loose_auto_plan_cache_time_thresholdOptimization time / total execution time >=
loose_auto_plan_cache_pct_threshold
The cached plan takes effect only after the query has been executed at least loose_auto_plan_cache_count_threshold times.
Use stored procedures
Add a query to the plan cache
CALL dbms_sql.add_plan_cache("schema_name", "query");Use this procedure in DEMAND mode to explicitly register a query for caching. Replace schema_name with the target schema and query with the SQL statement to cache.
Example:
CALL dbms_sql.add_plan_cache("test", "SELECT * FROM t_for_plan WHERE c1 > 1 AND c1 < 10");After this call, any query matching the template SELECT * FROM t_for_plan WHERE c1 > ? AND c1 < ? uses the cached execution plan.
View tables referenced in the plan cache
CALL dbms_sql.display_plan_cache_table()\GSample output:
*************************** 1. row ***************************
SCHEMA_NAME: test
TABLE_NAME: t_for_plan
REF_COUNT: 1
VERSION: 0
VERSION_TIME: 2023-03-10 17:21:35.605264| Field | Description |
|---|---|
SCHEMA_NAME | The schema where the referenced table resides |
TABLE_NAME | The name of the referenced table |
REF_COUNT | The number of cached plans that reference this table |
VERSION | The current version of the table in the plan cache |
VERSION_TIME | The time the current version was recorded |
Delete a cached execution plan
CALL dbms_sql.delete_sharing_by_rowid(row_id);row_id is the Id value from the mysql.sql_sharing table.
To find the row ID and delete the plan:
Query the plan cache for the target statement:
SELECT Id, Schema_name, Type, Digest_text FROM mysql.sql_sharing WHERE Type = 'PLAN_CACHE'\GSample output:
*************************** 1. row *************************** Id: 1 Schema_name: test Type: PLAN_CACHE Digest_text: SELECT * FROM `t_for_plan` WHERE `c1` > ? AND `c1` < ?Delete the plan using the
Idvalue:CALL dbms_sql.delete_sharing_by_rowid(1);
Query the plan cache
Execution plans are stored in the SQL Sharing module. Query the INFORMATION_SCHEMA.SQL_SHARING table to inspect cached plans:
SELECT TYPE, REF_BY, SQL_ID, SCHEMA_NAME, DIGEST_TEXT, PLAN_ID, PLAN, PLAN_EXTRA, EXTRA
FROM INFORMATION_SCHEMA.SQL_SHARING
WHERE json_contains(REF_BY, '"PLAN_CACHE"') OR json_contains(REF_BY, '"PLAN_CACHE(DEMAND)"')\GThe EXTRA field contains a PLAN_CACHE_INFO object showing the referenced tables, their versions, and the number of cache hits.
End-to-end example using DEMAND mode
Create a test table:
CREATE TABLE t_for_plan AS WITH RECURSIVE t(c1, c2, c3) AS ( SELECT 1, 1, 1 UNION ALL SELECT c1+1, c1 % 50, c1 % 200 FROM t WHERE c1 < 1000 ) SELECT c1, c2, c3 FROM t; CREATE INDEX i_c1_c2 ON t_for_plan(c1, c2);Set the caching mode to DEMAND. Use either method:
In the PolarDB console, go to the Parameters page, set
loose_plan_cache_typeto DEMAND, then reconnect to the database.In the current session:
SET plan_cache_type = demand;
Register the query for caching:
CALL dbms_sql.add_plan_cache("test", "SELECT * FROM t_for_plan WHERE c1 > 1 AND c1 < 10");Run the query:
SELECT * FROM t_for_plan WHERE c1 > 1 AND c1 < 10;Verify the cached plan:
SELECT TYPE, REF_BY, SQL_ID, SCHEMA_NAME, DIGEST_TEXT, PLAN_ID, PLAN, PLAN_EXTRA, EXTRA FROM INFORMATION_SCHEMA.SQL_SHARING WHERE json_contains(REF_BY, '"PLAN_CACHE"') OR json_contains(REF_BY, '"PLAN_CACHE(DEMAND)"')\GSample output:
*************************** 1. row *************************** TYPE: SQL REF_BY: ["PLAN_CACHE(DEMAND)"] SQL_ID: 9jrvksr3wjux6 SCHEMA_NAME: test DIGEST_TEXT: SELECT * FROM `t_for_plan` WHERE `c1` > ? AND `c1` < ? PLAN_ID: NULL PLAN: NULL PLAN_EXTRA: NULL EXTRA: {"TRACE_ROW_ID":1} *************************** 2. row *************************** TYPE: PLAN REF_BY: ["PLAN_CACHE"] SQL_ID: 9jrvksr3wjux6 SCHEMA_NAME: test DIGEST_TEXT: NULL PLAN_ID: 08xftakma6pm6 PLAN: /*+ INDEX(`t_for_plan`@`select#1` `i_c1_c2`) */ PLAN_EXTRA: {"access_type":["`t_for_plan`:range"]} EXTRA: {"PLAN_CACHE_INFO":{"tables":[`test`.`t_for_plan`], "versions":[0], "hits": 0}}The
PLAN_CACHE_INFOin theEXTRAfield shows the referenced table, its version, and the number of cache hits.
Performance data
A stress test on an 8-core, 32 GB cluster with 25 tables of 4 million rows each. The test query was SELECT id FROM sbtestN WHERE k IN(...) with an IN list of 20 values, run under both the Prepared Statement (PS) protocol and the non-PS protocol.
The following figure shows the performance test results for the PS protocol.

The following figure shows the performance test results for the non-PS protocol.

Auto Plan Cache improved throughput by more than 50% for both protocols compared to the baseline (OFF mode).
These results are from a workload where optimization time is a significant fraction of total query time. Workloads dominated by execution time rather than optimization time will see smaller gains. If your queries are short-running or their optimal plans vary significantly by parameter value, measure the impact before enabling the feature in production.