diff --git a/TOC-tidb-cloud.md b/TOC-tidb-cloud.md index 522afa658bc43..61003e8731ecd 100644 --- a/TOC-tidb-cloud.md +++ b/TOC-tidb-cloud.md @@ -171,7 +171,8 @@ - [Wrong Index Solution](/wrong-index-solution.md) - [Distinct Optimization](/agg-distinct-optimization.md) - [Cost Model](/cost-model.md) - - [Prepare Execution Plan Cache](/sql-prepared-plan-cache.md) + - [Prepared Execution Plan Cache](/sql-prepared-plan-cache.md) + - [Non-Prepared Execution Plan Cache](/sql-non-prepared-plan-cache.md) - Control Execution Plans - [Overview](/control-execution-plan.md) - [Optimizer Hints](/optimizer-hints.md) diff --git a/TOC.md b/TOC.md index 91bea57eb5fc7..e86a22b5528d9 100644 --- a/TOC.md +++ b/TOC.md @@ -255,7 +255,8 @@ - [Wrong Index Solution](/wrong-index-solution.md) - [Distinct Optimization](/agg-distinct-optimization.md) - [Cost Model](/cost-model.md) - - [Prepare Execution Plan Cache](/sql-prepared-plan-cache.md) + - [Prepared Execution Plan Cache](/sql-prepared-plan-cache.md) + - [Non-Prepared Execution Plan Cache](/sql-non-prepared-plan-cache.md) - Control Execution Plans - [Overview](/control-execution-plan.md) - [Optimizer Hints](/optimizer-hints.md) diff --git a/latency-breakdown.md b/latency-breakdown.md index d7f5c74997dec..bd037016f8e54 100644 --- a/latency-breakdown.md +++ b/latency-breakdown.md @@ -66,7 +66,7 @@ e2e duration = - `tidb_server_get_token_duration_seconds` records the duration of Token waiting. This is usually less than 1 millisecond and is small enough to be ignored. - `tidb_session_parse_duration_seconds` records the duration of parsing SQL queries to an Abstract Syntax Tree (AST), which can be skipped by [`PREPARE/EXECUTE` statements](/develop/dev-guide-optimize-sql-best-practices.md#use-prepare). -- `tidb_session_compile_duration_seconds` records the duration of compiling an AST to an execution plan, which can be skipped by [SQL prepare execution plan cache](/sql-prepared-plan-cache.md). +- `tidb_session_compile_duration_seconds` records the duration of compiling an AST to an execution plan, which can be skipped by [SQL prepared execution plan cache](/sql-prepared-plan-cache.md). - `tidb_session_execute_duration_seconds{type="general"}` records the duration of execution, which mixes all types of user queries. This needs to be broken down into fine-grained durations for analyzing performance issues or bottlenecks. Generally, OLTP (Online Transactional Processing) workload can be divided into read and write queries, which share some critical code. The following sections describe latency in [read queries](#read-queries) and [write queries](#write-queries), which are executed differently. diff --git a/media/tidb-non-prepared-plan-cache-metrics.png b/media/tidb-non-prepared-plan-cache-metrics.png new file mode 100644 index 0000000000000..42c62bfdc6e8d Binary files /dev/null and b/media/tidb-non-prepared-plan-cache-metrics.png differ diff --git a/sql-non-prepared-plan-cache.md b/sql-non-prepared-plan-cache.md new file mode 100644 index 0000000000000..a7c1f3e06ec74 --- /dev/null +++ b/sql-non-prepared-plan-cache.md @@ -0,0 +1,170 @@ +--- +title: SQL Non-Prepared Execution Plan Cache +summary: Learn about the principle, usage, and examples of the SQL non-prepared execution plan cache in TiDB. +--- + +# SQL Non-Prepared Execution Plan Cache + +> **Warning:** +> +> The non-prepared execution plan cache is an experimental feature. It is not recommended that you use it in the production environment. This feature might be changed or removed without prior notice. If you find a bug, you can report an [issue](https://github.com/pingcap/tidb/issues) on GitHub. + +TiDB supports execution plan caching for some non-`PREPARE` statements, similar to the [`Prepare`/`Execute` statements](/sql-prepared-plan-cache.md). This feature allows these statements to skip the optimization phase and improve performance. + +## Principle + +The non-prepared plan cache is a session-level feature that is independent of the [prepared plan cache](/sql-prepared-plan-cache.md), and the cached plans do not affect each other. The basic principle of the non-prepared plan cache is as follows: + +1. After you enable the non-prepared plan cache, TiDB first parameterizes the query based on the abstract syntax tree (AST). For example, `SELECT * FROM t WHERE b < 10 AND a = 1` is parameterized as `SELECT * FROM t WHERE b < ? and a = ?`. +2. Then, TiDB uses the parameterized query to search the non-prepared plan cache. +3. If a reusable plan is found, it is directly used and the optimization phase is skipped. +4. Otherwise, the optimizer generates a new plan and adds it back into the cache for reuse in the subsequent query. + +## Usage + +To enable or disable the non-prepared plan cache, you can set the [`tidb_enable_non_prepared_plan_cache`](/system-variables.md#tidb_enable_non_prepared_plan_cache) system variable. You can also control the size of the non-prepared plan cache using the [`tidb_non_prepared_plan_cache_size`](/system-variables.md#tidb_non_prepared_plan_cache_size) system variable. When the number of cached plans exceeds `tidb_non_prepared_plan_cache_size`, TiDB evicts plans using the least recently used (LRU) strategy. + +## Example + +The following example shows how to use the non-prepared plan cache: + +1. Create a table `t` for testing: + + ```sql + CREATE TABLE t (a INT, b INT, KEY(b)); + ``` + +2. Enable the non-prepared plan cache: + + ```sql + SET tidb_enable_non_prepared_plan_cache = true; + ``` + +3. Execute the following two queries: + + ```sql + SELECT * FROM t WHERE b < 10 AND a = 1; + SELECT * FROM t WHERE b < 5 AND a = 2; + ``` + +4. Check whether the second query hits the cache: + + ```sql + SELECT @@last_plan_from_cache; + ``` + + If the value of `last_plan_from_cache` in the output is `1`, it means that the execution plan of the second query comes from the cache: + + ```sql + +------------------------+ + | @@last_plan_from_cache | + +------------------------+ + | 1 | + +------------------------+ + 1 row in set (0.00 sec) + ``` + +## Restrictions + +TiDB only caches one plan for a parameterized query. For example, the queries `SELECT * FROM t WHERE a < 1` and `SELECT * FROM t WHERE a < 100000` share the same parameterized form, `SELECT * FROM t WHERE a < ?`, and thus share the same plan. + +If this causes performance issues, you can use the `ignore_plan_cache()` hint to ignore plans in the cache, so that the optimizer generates a new execution plan for the SQL every time. If the SQL cannot be modified, you can create a binding to solve the problem. For example, `CREATE BINDING FOR SELECT ... USING SELECT /*+ ignore_plan_cache() */ ...`. + +Due to the preceding risks and the fact that the execution plan cache only provides significant benefits for simple queries (if a query is complex and takes a long time to execute, using the execution plan cache might not be very helpful), TiDB has strict restrictions on the scope of non-prepared plan cache. The restrictions are as follows: + +- Queries or plans that are not supported by the [Prepared plan cache](/sql-prepared-plan-cache.md) are also not supported by the non-prepared plan cache. +- Currently, only point get or range queries on a single table that contain `Scan`, `Selection`, or `Projection` operators are supported, such as `SELECT * FROM t WHERE a < 10 AND b in (1, 2)`. +- Queries that contain complex operators such as `Agg`, `Limit`, `Window`, or `Sort` are not supported. +- Queries that contain non-range query conditions are not supported, such as: + - `LIKE` is not supported, such as `c LIKE 'c%'`. + - `+` operation is not supported, such as `a+1 < 2`. +- Queries that filter on columns of `JSON`, `ENUM`, `SET`, or `BIT` type are not supported, such as `SELECT * FROM t WHERE json_col = '{}'`. +- Queries that filter on `NULL` values are not supported, such as `SELECT * FROM t WHERE a is NULL`. +- Queries with more than 50 parameters after parameterization are not supported, such as `SELECT * FROM t WHERE a in (1, 2, 3, ... 51)`. +- Queries that access partitioned tables, virtual columns, temporary tables, views, or memory tables are not supported, such as `SELECT * FROM INFORMATION_SCHEMA.COLUMNS`, where `COLUMNS` is a TiDB memory table. +- Queries with hints, subqueries, or locks are not supported. +- DML statements are not supported. + +## Diagnostics + +After enabling the non-prepared plan cache, you can execute the `EXPLAIN FORMAT='plan_cache' SELECT ...` statement to verify whether the query can hit the cache. For queries that cannot hit the cache, the system returns the reason in a warning. + +Note that if you do not add `FORMAT='plan_cache'`, the `EXPLAIN` statement will never hit the cache. + +To verify whether the query hits the cache, execute the following `EXPLAIN FORMAT='plan_cache'` statement: + +```sql +EXPLAIN FORMAT='plan_cache' SELECT * FROM t WHERE a+2 < 10; +``` + +The output is as follows: + +```sql +3 rows in set, 1 warning (0.00 sec) +``` + +To view the queries that cannot hit the cache, execute `SHOW warnings;`: + +```sql +SHOW warnings; +``` + +The output is as follows: + +```sql ++---------+------+-----------------------------------------------------------------------+ +| Level | Code | Message | ++---------+------+-----------------------------------------------------------------------+ +| Warning | 1105 | skip non-prep plan cache: query has some unsupported binary operation | ++---------+------+-----------------------------------------------------------------------+ +1 row in set (0.00 sec) +``` + +In the preceding example, the query cannot hit the cache because the non-prepared plan cache does not support the `+` operation. + +## Monitoring + +After enabling the non-prepared plan cache, you can monitor the memory usage, number of plans in the cache, and cache hit rate in the following panes: + +![non-prepare-plan-cache](/media/tidb-non-prepared-plan-cache-metrics.png) + +You can also monitor the cache hit rate in the `statements_summary` table and slow query log. The following shows how to view the cache hit rate in the `statements_summary` table: + +1. Create a table `t`: + + ```sql + CREATE TABLE t (a int); + ``` + +2. Enable the non-prepared plan cache: + + ```sql + SET @@tidb_enable_non_prepared_plan_cache=1; + ``` + +3. Execute the following three queries: + + ```sql + SELECT * FROM t WHERE a<1; + SELECT * FROM t WHERE a<2; + SELECT * FROM t WHERE a<3; + ``` + +4. Query the `statements_summary` table to view the cache hit rate: + + ```sql + SELECT digest_text, query_sample_text, exec_count, plan_in_cache, plan_cache_hits FROM INFORMATION_SCHEMA.STATEMENTS_SUMMARY WHERE digest_text LIKE '%SELECT * FROM %'; + ``` + + The output is as follows: + + ```sql + +---------------------------------+------------------------------------------+------------+---------------+-----------------+ + | digest_text | query_sample_text | exec_count | plan_in_cache | plan_cache_hits | + +---------------------------------+------------------------------------------+------------+---------------+-----------------+ + | SELECT * FROM `t` WHERE `a` < ? | SELECT * FROM t WHERE a<1 [arguments: 1] | 3 | 1 | 2 | + +---------------------------------+------------------------------------------+------------+---------------+-----------------+ + 1 row in set (0.01 sec) + ``` + + From the output, you can see that the query was executed three times and hit the cache twice. diff --git a/sql-prepared-plan-cache.md b/sql-prepared-plan-cache.md index eec038a11ea54..90af89a97c6cc 100644 --- a/sql-prepared-plan-cache.md +++ b/sql-prepared-plan-cache.md @@ -1,10 +1,10 @@ --- -title: SQL Prepare Execution Plan Cache -summary: Learn about SQL Prepare Execution Plan Cache in TiDB. +title: SQL Prepared Execution Plan Cache +summary: Learn about SQL Prepared Execution Plan Cache in TiDB. aliases: ['/tidb/dev/sql-prepare-plan-cache'] --- -# SQL Prepare Execution Plan Cache +# SQL Prepared Execution Plan Cache TiDB supports execution plan caching for `Prepare` and `Execute` queries. This includes both forms of prepared statements: diff --git a/system-variables.md b/system-variables.md index a1bff429d34aa..284365bf5ee1c 100644 --- a/system-variables.md +++ b/system-variables.md @@ -1513,13 +1513,13 @@ MPP is a distributed computing framework provided by the TiFlash engine, which a > **Warning:** > -> The feature controlled by this variable is not fully functional in the current TiDB version. Do not change the default value. +> The non-prepared execution plan cache is an experimental feature. It is not recommended that you use it in the production environment. This feature might be changed or removed without prior notice. If you find a bug, you can report an [issue](https://github.com/pingcap/tidb/issues) on GitHub. - Scope: SESSION | GLOBAL - Persists to cluster: Yes - Type: Boolean - Default value: `OFF` -- This variable controls whether to enable the General Plan Cache feature. +- This variable controls whether to enable the [Non-prepared plan cache](/sql-non-prepared-plan-cache.md) feature. ### tidb_enable_gogc_tuner New in v6.4.0 @@ -2277,14 +2277,14 @@ For a system upgraded to v5.0 from an earlier version, if you have not modified > **Warning:** > -> The feature controlled by this variable is not fully functional in the current TiDB version. Do not change the default value. +> The non-prepared execution plan cache is an experimental feature. It is not recommended that you use it in the production environment. This feature might be changed or removed without prior notice. If you find a bug, you can report an [issue](https://github.com/pingcap/tidb/issues) on GitHub. - Scope: SESSION | GLOBAL - Persists to cluster: Yes - Type: Integer - Default value: `100` - Range: `[1, 100000]` -- This variable controls the maximum number of execution plans that can be cached by General Plan Cache. +- This variable controls the maximum number of execution plans that can be cached by [Non-prepared plan cache](/sql-non-prepared-plan-cache.md). ### tidb_generate_binary_plan New in v6.2.0 diff --git a/tidb-cloud/tidb-cloud-sql-tuning-overview.md b/tidb-cloud/tidb-cloud-sql-tuning-overview.md index 826811e7fbaa9..b21f7b26a72d7 100644 --- a/tidb-cloud/tidb-cloud-sql-tuning-overview.md +++ b/tidb-cloud/tidb-cloud-sql-tuning-overview.md @@ -49,7 +49,7 @@ After parsing the original query text by `parser` and basic validity verificatio Through these equivalence changes, the query can become easier to handle in the logical execution plan. After the equivalence changes, TiDB gets a query plan structure that is equivalent to the original query, and then gets a final execution plan based on the data distribution and the specific execution overhead of an operator. For more information, see [SQL Physical Optimization](/sql-physical-optimization.md). -Also, TiDB can choose to enable execution plan cache to reduce the creation overhead of the execution plan when executing the `PREPARE` statement, as introduced in [Prepare Execution Plan Cache](/sql-prepared-plan-cache.md). +Also, TiDB can choose to enable execution plan cache to reduce the creation overhead of the execution plan when executing the `PREPARE` statement, as introduced in [Prepared Execution Plan Cache](/sql-prepared-plan-cache.md). ### Optimize full table scan