Auto plan cache

更新时间:
复制 MD 格式

You can use the auto plan cache feature of PolarDB for MySQL to cache execution plans for SQL statements. This shortens query optimization time and improves query performance. This topic describes the background information, prerequisites, parameters, and interfaces for the auto plan cache feature.

Background information

Choosing an execution plan involves many factors, such as statistics, different join orders, and query transformations. The optimization time varies for different query statements. For some SQL statements, the query optimization time can be a large part of the total running time. If these statements run frequently, the long optimization time increases the system load. Caching and reusing execution plans reduces the optimization time for each run. This improves query performance, lowers the database load, and increases throughput capacity.

For many other queries, the optimization time is small, but the running time is heavily influenced by the execution plan. Different parameter values in an SQL statement can correspond to different optimal execution plans. In some scenarios, MySQL retrieves actual data from the engine based on parameter values for further optimization.

Using a fixed execution plan for these queries may not improve query response time or reduce load overhead. It can even cause performance regression.

PolarDB for MySQL provides the auto plan cache feature to improve the query performance of SQL statements with long optimization times, reduce system load, and avoid performance regression from fixed execution plans. The auto plan cache feature has three modes: AUTO, DEMAND, and ENFORCE. You can set the loose_plan_cache_type parameter to one of these modes to cache execution plans in the plan cache. This reduces optimization time and improves query performance. A cached execution plan is automatically invalidated if the statistics of a referenced table change or if a Data Definition Language (DDL) operation is performed on a referenced table.

Prerequisites

Your PolarDB cluster must meet one of the following version requirements:

  • PolarDB for MySQL 8.0.1 with a revision version of 8.0.1.1.33 or later.

  • PolarDB for MySQL 8.0.2 with a revision version of 8.0.2.2.12 or later.

Parameters

You can set the parameters in the following table in the PolarDB console. For more information, see Set cluster and node parameters.

Parameter

Description

loose_plan_cache_type

The mode for auto plan cache. Valid values:

  • OFF (Default): Disables the auto plan cache feature.

  • AUTO: Automatically caches the execution plans of SQL statements that meet the caching conditions.

    Note

    Caching conditions:

    The execution plan for an SQL statement is cached if its total running time is greater than or equal to the value of the loose_auto_plan_cache_time_threshold parameter, and the percentage of optimization time in the total running time is greater than or equal to the value of the loose_auto_plan_cache_pct_threshold parameter.

  • DEMAND: Caches the execution plans of specified SQL statements.

  • ENFORCE: Forcibly caches the execution plans of all SQL statements.

loose_plan_cache_expire_time

If an execution plan in the plan cache is not hit within this time, its memory is reclaimed. The unit is seconds.

Value range: 0 to 4294967295. Default value: 1800.

loose_auto_plan_cache_pct_threshold

The threshold for the percentage of optimization time in the total running time of a statement.

Value range: 0 to 100. Default value: 20.

loose_auto_plan_cache_time_threshold

The threshold for the total running time of an SQL statement. The unit is microseconds.

Value range: 0 to 18446744073709551615. Default value: 400.

loose_auto_plan_cache_count_threshold

When the loose_plan_cache_type parameter is set to AUTO, this is the threshold for the number of times the execution plan of a qualifying SQL statement is cached.

Value range: 0 to 18446744073709551615. Default value: 512.

Note

The cached execution plan takes effect only when the number of times it has been cached is greater than or equal to the value of the loose_auto_plan_cache_count_threshold parameter.

Interface descriptions

  • dbms_sql.add_plan_cache(schema, query): Caches the execution plan of a specified SQL statement in the plan cache.

    When the loose_plan_cache_type parameter is set to DEMAND, you can use this built-in stored procedure to cache the execution plan of a specified SQL statement. The following example shows how:

    CALL dbms_sql.add_plan_cache("test", "SELECT * FROM t_for_plan WHERE c1 > 1 AND c1 < 10");

    After this statement is executed, the execution plan is cached for any SQL statement that matches the SELECT * FROM t_for_plan WHERE c1 > ? AND c1 < ? template.

  • dbms_sql.display_plan_cache_table(): Displays information about the tables referenced in the current plan cache. The following example shows how:

    CALL dbms_sql.display_plan_cache_table()\G

    The following result is returned:

    *************************** 1. row ***************************
     SCHEMA_NAME: test
      TABLE_NAME: t_for_plan
       REF_COUNT: 1
         VERSION: 0
    VERSION_TIME: 2023-03-10 17:21:35.605264

    The following table describes the parameters.

    • SCHEMA_NAME: The name of the schema where the referenced table resides.

    • TABLE_NAME: The name of the referenced table.

    • REF_COUNT: The number of times the table is referenced in the plan cache.

    • VERSION: The version of the referenced table in the plan cache.

    • VERSION_TIME: The time when the current version of the table was referenced.

  • dbms_sql.delete_sharing_by_rowid(row_id): Deletes the execution plan of a specified SQL statement.

    The row_id is the row ID of the execution plan stored in the mysql.sql_sharing table.

    Example

    1. Run the following command to view the execution plan information in the cache.

      SELECT Id, Schema_name, Type, Digest_text FROM mysql.sql_sharing WHERE Type = 'PLAN_CACHE'\G

      The following result is returned:

      *************************** 1. row ***************************
               Id: 1
      Schema_name: test
             Type: PLAN_CACHE
      Digest_text: SELECT * FROM `t_for_plan` WHERE `c1` > ? AND `c1` < ?

      The query result shows that the row_id value is 1.

    2. Delete the execution plan from the previous query.

      CALL dbms_sql.delete_sharing_by_rowid(1);

Get cached information from the plan cache

The execution plans of SQL statements are stored in the SQL Sharing module. You can run the following SQL statement to query the cached information in the plan cache from the INFORMATION_SCHEMA.SQL_SHARING table.

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)"')\G

Example

  1. Prepare the data.

    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);
  2. Set the auto plan cache mode to DEMAND.

    You can set the auto plan cache mode in one of the following two ways.

    • On the Parameters page in the PolarDB console, set the loose_plan_cache_type parameter to DEMAND. After the setting is complete, disconnect from and then reconnect to the database.

    • In the current database connection, run the following command to set the plan_cache_type parameter for the current session to demand.

      SET plan_cache_type=demand;
  3. Run the following command to cache the execution plan of the specified SQL statement in the plan cache.

    CALL dbms_sql.add_plan_cache("test", "SELECT * FROM t_for_plan WHERE c1 > 1 AND c1 < 10");
  4. Run the query statement.

    SELECT * FROM t_for_plan WHERE c1 > 1 AND c1 < 10;
  5. Query the cached information in the plan cache.

    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)"')\G

    The following result is returned:

    *************************** 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}}

    In the EXTRA field, PLAN_CACHE_INFO shows the referenced tables, the versions of the referenced tables, and the number of execution plan hits.

Query performance

A stress test was conducted on an 8 core, 32 GB cluster. The database contained 25 tables, with each table storing 4 million rows of data. The stress test used the SQL statement SELECT id FROM sbtestN WHERE k IN(...), where the length of the IN list was 20. Performance was tested with the loose_plan_cache_type parameter set to OFF, AUTO, and ENFORCE under both Prepared Statement (PS) and non-PS protocols. The test results are as follows:

  • Performance test results under the PS protocol: PS协议下的查询性能

  • Performance test results under the non-PS protocol: 非PS协议下的查询性能

The test results show that the auto plan cache feature improves performance by more than 50% under both PS and non-PS protocols.