All Products
Search
Document Center

PolarDB:Archive a partitioned table in CSV format

Last Updated:Apr 30, 2026

The data lifecycle management (DLM) feature helps you reduce storage costs and improve efficiency. It automatically and periodically archives infrequently accessed cold data from PolarStore to a low-cost storage medium, such as Object Storage Service (OSS).

Prerequisites

  • Your cluster must run PolarDB for MySQL 8.0.2, revision 8.0.2.2.34.1 or later.

    Note
    • To check your cluster version, see Query the engine version.

    • If your cluster runs PolarDB for MySQL 8.0.2, revision 8.0.2.2.11.1 or later, the DLM feature does not record operations in the binary log.

  • You must enable cold data archiving before you can use DLM policies. For more information, see Enable cold data archiving.

    Note

    If you do not enable the cold data archiving feature, the following error is returned:

    ERROR 8158 (HY000): [Data Lifecycle Management] DLM storage engine is not support. The value of polar_dlm_storage_mode is OFF.

Limitations

  • The DLM feature supports only partitioned tables that do not contain subpartitions. The partitioning method must be RANGE COLUMN.

  • You cannot use the DLM feature on a partitioned table that has a global secondary index (GSI).

  • PolarDB for MySQL does not support modifying a DLM policy. To modify a policy, you must first delete the existing policy and then create a new one.

  • If a DLM policy exists on a table, do not perform DDL operations that cause schema inconsistencies between the source table and the archive table, such as adding or deleting columns or modifying column data types. Such inconsistencies can prevent subsequently archived data from being parsed. Before you perform these DDL operations, you must delete the DLM policy from the table. To resume automatic data archiving, create a new DLM policy and specify a new name for the archive table. The new name cannot be the same as any previously used archive table name.

  • Use INTERVAL RANGE partitioning to automatically extend partitions and the DLM feature to archive data from infrequently used partitions to OSS.

    Note

    INTERVAL RANGE partitioning is supported only for clusters that run PolarDB for MySQL 8.0.2, revision 8.0.2.2.0 or later.

  • You must specify a DLM policy when you run the CREATE TABLE or ALTER TABLE statement.

  • The SHOW CREATE TABLE statement does not display DLM policies. You can view all DLM policies in the mysql.dlm_policies table.

Precautions

  • After cold data is archived, the archive table in OSS is read-only, and query performance may be slow. You must test in advance to ensure that the query performance meets your requirements.

  • After a partition from a partitioned table is archived to OSS, the data in that partition becomes read-only. You cannot perform DDL operations on the partitioned table.

  • Backup operations do not include data that has been archived to OSS. Data in OSS does not support point-in-time recovery.

Syntax

Create a policy

  • Create a DLM policy with CREATE TABLE

    CREATE TABLE [IF NOT EXISTS] tbl_name
        (create_definition,...)
        [table_options]
        [partition_options]
        [dlm_add_options]
    
    dlm_add_options:
        DLM ADD
            [(dlm_policy_definition [, dlm_policy_definition] ...)]
    
    dlm_policy_definition:
        POLICY policy_name
        [TIER TO TABLE/TIER TO PARTITION/TIER TO NONE]
        [ENGINE [=] engine_name]
        [STORAGE SCHEMA_NAME [=] storage_schema_name]
        [STORAGE TABLE_NAME [=] storage_table_name]
        [STORAGE [=] OSS]
        [READ ONLY]
        [COMMENT 'comment_string']
        [EXTRA_INFO 'extra_info']
        ON [(PARTITIONS OVER num)]           
  • Create a DLM policy with ALTER TABLE

    ALTER TABLE tbl_name
        [alter_option [, alter_option] ...]
        [partition_options]
        [dlm_add_options]
    
    dlm_add_options:
        DLM ADD
            [(dlm_policy_definition [, dlm_policy_definition] ...)]
    
    dlm_policy_definition:
        POLICY policy_name
        [TIER TO TABLE/TIER TO PARTITION/TIER TO NONE]
        [ENGINE [=] engine_name]
        [STORAGE SCHEMA_NAME [=] storage_schema_name]
        [STORAGE TABLE_NAME [=] storage_table_name]
        [STORAGE [=] OSS]
        [READ ONLY]
        [COMMENT 'comment_string']
        [EXTRA_INFO 'extra_info']
        ON [(PARTITIONS OVER num)]      

DLM policy parameters

Parameter

Required

Description

tbl_name

Yes

The table name.

policy_name

Yes

The policy name.

TIER TO TABLE

Yes

Archives data to a new OSS foreign table.

TIER TO PARTITION

Yes

Converts hot data partitions into cold data partitions stored in OSS within the same table, creating a hybrid partitioned table.

Note
  • This feature is in canary release. To use this feature, go to Quota Center, find the quota name that corresponds to the polardb_mysql_hybrid_partition quota ID, and click Apply in the Actions column.

  • You can archive the partitions of a partitioned table to OSS only if your cluster runs PolarDB for MySQL 8.0.2, revision 8.0.2.2.17 or later.

  • When you use this feature, make sure that the total number of partitions in the partitioned table does not exceed 8,192.

TIER TO NONE

Yes

Deletes the data from the oldest partitions instead of archiving it.

engine_name

No

The storage engine for the archived data. Currently, data can be archived only to the CSV engine.

storage_schema_name

No

The database for the archive table. This defaults to the source table's database.

storage_table_name

No

The name of the archive table. If unspecified, it defaults to <source_table_name>_<dlm_policy_name>.

STORAGE [=] OSS

No

Stores the archived data in OSS. This is the default.

READ ONLY

No

Makes the archived data read-only. This is the default.

comment_string

No

The comment for the DLM policy.

extra_info

No

Specifies the OSS_FILE_FILTER information for the destination OSS table.

Note
  • Archiving partitions to OSS requires your cluster to run the Enterprise Edition of PolarDB for MySQL 8.0.2, revision 8.0.2.2.25 or later.

  • This feature takes effect only if the destination table does not exist. In this case, the system automatically generates the FILE_FILTER attribute based on the OSS_FILE_FILTER parameter in EXTRA_INFO when the destination OSS table is created. If the destination table already exists, the existing file filter is used.

The format of EXTRA_INFO is {"oss_file_filter":"field_filter[,field_filter]"}, where field_filter is defined as follows:

field_filter := field_name[:filter_type]
filter_type := bloom

ON (PARTITIONS OVER num)

Yes

Archives data when the number of partitions is greater than num.

Manage a policy

  • Enable a DLM policy.

    ALTER TABLE table_name DLM ENABLE POLICY [(dlm_policy_name [, dlm_policy_name] ...)]
  • Disable a DLM policy.

    ALTER TABLE table_name DLM DISABLE POLICY [(dlm_policy_name [, dlm_policy_name] ...)]
  • Delete a DLM policy.

    ALTER TABLE table_name DLM DROP POLICY [(dlm_policy_name [, dlm_policy_name] ...)]

In these statements, table_name is the name of the table, and dlm_policy_name is the name of the policy to manage. You can specify multiple policy names.

Execute a policy

  • Execute all DLM policies on all tables in the current cluster.

    CALL dbms_dlm.execute_all_dlm_policies();
  • Execute the DLM policies on a single table.

    CALL dbms_dlm.execute_table_dlm_policies('database_name', 'table_name');

    In this statement, database_name is the name of the database that contains the table, and table_name is the name of the table.

You can use the MySQL event feature to execute DLM policies during your cluster's maintenance window. This method prevents database performance from being affected during peak business hours and allows you to periodically move expired data to reduce storage costs. Use the following syntax to execute a DLM policy with an event:

CREATE
    EVENT
    [IF NOT EXISTS]
    event_name
    ON SCHEDULE schedule
    [COMMENT 'comment']
    DO event_body;

schedule: {
  EVERY interval
  [STARTS timestamp [+ INTERVAL interval] ...]
}

interval:
    quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
              WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
              DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}

event_body: {
      CALL dbms_dlm.execute_all_dlm_policies();
    | CALL dbms_dlm.execute_table_dlm_policies('database_name', 'table_name');
}

The following table describes the parameters.

Parameter

Required

Description

event_name

Yes

The name of the event.

schedule

Yes

The time and frequency at which to run the event.

comment

No

The comment for the event.

event_body

Yes

The content that the event executes. This must be a statement that executes a DLM policy.

Note
  • If you use CALL dbms_dlm.execute_all_dlm_policies(), the event executes all DLM policies on the cluster. Therefore, you must create only one such event per cluster.

  • If you use CALL dbms_dlm.execute_table_dlm_policies('database_name', 'table_name');, the event executes all DLM policies only on a specific table. Therefore, create an event for each table that requires scheduled archiving.

interval

Yes

The execution frequency of the event.

timestamp

Yes

The time to start running the event.

database_name

Yes

The database name.

table_name

Yes

The table name.

For more information about the MySQL EVENT feature, see the official MySQL documentation for CREATE EVENT.

For usage examples, see Examples of archiving cold data to OSS.

Examples

Archive data to a foreign table

  1. Create a DLM policy

    The following example creates a partitioned table named sales that uses the order_time column as the partition key. The table has an INTERVAL policy and a DLM policy:

    • INTERVAL policy: When inserted data falls outside the existing partition range, a new partition is automatically created with a time interval of one year.

    • DLM policy: The table is defined to retain only three partitions. When the number of partitions exceeds three, the DLM policy is triggered and performs one of the following actions:

      • If the OSS foreign table sales_history does not exist, a new OSS foreign table named sales_history is created, and the cold data is archived to the sales_history table.

      • If the sales_history external table exists, and the sales_history table is on the built-in OSS, the cold data is directly archived to the sales_history external table.

    Note

    To create a table with INTERVAL RANGE partitioning, make sure that all prerequisites are met. For more information about INTERVAL, see INTERVAL RANGE partitioning.

    1. Create the sales table with a DLM policy.

      CREATE TABLE `sales` (
        `id` int DEFAULT NULL,
        `name` varchar(20) DEFAULT NULL,
        `order_time` datetime NOT NULL,
         PRIMARY KEY (`order_time`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
      PARTITION BY RANGE  COLUMNS(order_time) INTERVAL(YEAR, 1)
      (PARTITION p20200101000000 VALUES LESS THAN ('2020-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION p20210101000000 VALUES LESS THAN ('2021-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION p20220101000000 VALUES LESS THAN ('2022-01-01 00:00:00') ENGINE = InnoDB)
      DLM ADD POLICY test_policy TIER TO TABLE ENGINE=CSV STORAGE=OSS READ ONLY
      STORAGE TABLE_NAME = 'sales_history' EXTRA_INFO '{"oss_file_filter":"id,name:bloom"}' ON (PARTITIONS OVER 3);

      The DLM policy for the table is named test_policy. When the number of partitions exceeds three, the policy archives the cold data from the source table in CSV format to OSS. The resulting archive table is named sales_history and is read-only. If the OSS archive table does not exist, the system automatically creates it and adds an OSS_FILE_FILTER to the id and name columns.

    2. The DLM policies for the current table are stored in the system table mysql.dlm_policies. You can query this table to view the details of the DLM policies. For more information about the mysql.dlm_policies table, see Table structure description. View the structure of the mysql.dlm_policies table.

      mysql> SELECT * FROM mysql.dlm_policies\G

      Sample output:

      *************************** 1. row ***************************
                         Id: 3
               Table_schema: test
                 Table_name: sales
                Policy_name: test_policy
                Policy_type: TABLE
               Archive_type: PARTITION COUNT
               Storage_mode: READ ONLY
             Storage_engine: CSV
              Storage_media: OSS
        Storage_schema_name: test
         Storage_table_name: sales_history
            Data_compressed: OFF
       Compressed_algorithm: NULL
                    Enabled: ENABLED
            Priority_number: 10300
      Tier_partition_number: 3
             Tier_condition: NULL
                 Extra_info: {"oss_file_filter": "id,name:bloom,order_time"}
                    Comment: NULL
      1 row in set (0.03 sec)      

      Currently, the sales table has three partitions, so no data is archived.

    3. Insert 3,000 rows of test data into the sales partitioned table. This ensures that the data exceeds the defined partition range and triggers the INTERVAL policy to automatically create new partitions.

      DROP PROCEDURE IF EXISTS proc_batch_insert;
      delimiter $$
      CREATE PROCEDURE proc_batch_insert(IN begin INT, IN end INT, IN name VARCHAR(20))
      BEGIN
      SET @insert_stmt = concat('INSERT INTO ', name, ' VALUES(? , ?, ?);');
      PREPARE stmt from @insert_stmt;
      WHILE begin <= end DO
      SET @ID1 = begin;
      SET @NAME = CONCAT(begin+begin*281313, '@stiven');
      SET @TIME = from_days(begin + 737600);
      EXECUTE stmt using @ID1, @NAME, @TIME;
      SET begin = begin + 1;
      END WHILE;
      END;
      $$
      delimiter ;
      CALL proc_batch_insert(1, 3000, 'sales');
    4. The INTERVAL policy is triggered, which adds new partitions to the sales table. The table structure is now as follows:

      mysql> SHOW CREATE TABLE sales\G

      Sample output:

      *************************** 1. row ***************************       
            Table: sales
      Create Table: CREATE TABLE `sales` (  
        `id` int(11) DEFAULT NULL,  
        `name` varchar(20) DEFAULT NULL,  
        `order_time` datetime NOT NULL,  
         PRIMARY KEY (`order_time`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
      /*!50500 PARTITION BY RANGE  COLUMNS(order_time) */ 
      /*!99990 800020200 INTERVAL(YEAR, 1) */
      /*!50500 (PARTITION p20200101000000 VALUES LESS THAN ('2020-01-01 00:00:00') ENGINE = InnoDB, 
      PARTITION p20210101000000 VALUES LESS THAN ('2021-01-01 00:00:00') ENGINE = InnoDB, 
      PARTITION p20220101000000 VALUES LESS THAN ('2022-01-01 00:00:00') ENGINE = InnoDB, 
      PARTITION _p20230101000000 VALUES LESS THAN ('2023-01-01 00:00:00') ENGINE = InnoDB, 
      PARTITION _p20240101000000 VALUES LESS THAN ('2024-01-01 00:00:00') ENGINE = InnoDB, 
      PARTITION _p20250101000000 VALUES LESS THAN ('2025-01-01 00:00:00') ENGINE = InnoDB, 
      PARTITION _p20260101000000 VALUES LESS THAN ('2026-01-01 00:00:00') ENGINE = InnoDB, 
      PARTITION _p20270101000000 VALUES LESS THAN ('2027-01-01 00:00:00') ENGINE = InnoDB, 
      PARTITION _p20280101000000 VALUES LESS THAN ('2028-01-01 00:00:00') ENGINE = InnoDB) */
      1 row in set (0.03 sec)

      The new partitions increase the total partition count to more than three. This meets the condition for the DLM policy, and the data is now ready for archiving.

  2. Execute the DLM policy

    1. You can execute the DLM policy directly by using an SQL statement, or you can run it periodically by using the MySQL EVENT feature. For example, assume your maintenance window starts at 01:00 every day, beginning on October 11, 2022. You can create the following event to run the DLM policy daily at 01:00.

      CREATE EVENT dlm_system_base_event
             ON SCHEDULE EVERY 1 DAY
          STARTS '2022-10-11 01:00:00'
          do CALL 
      dbms_dlm.execute_all_dlm_policies();

      After 01:00, this event executes all DLM policies on all tables.

    2. Run the following command to view the sales table structure:

      mysql> SHOW CREATE TABLE sales\G

      Sample output:

      *************************** 1. row ***************************
             Table: sales
      Create Table: CREATE TABLE `sales` (  
        `id` int(11) DEFAULT NULL,  
        `name` varchar(20) DEFAULT NULL,  
        `order_time` datetime NOT NULL,  
         PRIMARY KEY (`order_time`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
      /*!50500 PARTITION BY RANGE  COLUMNS(order_time) */ 
      /*!99990 800020200 INTERVAL(YEAR, 1) */
      /*!50500 (PARTITION _p20260101000000 VALUES LESS THAN ('2026-01-01 00:00:00') ENGINE = InnoDB,
      PARTITION _p20270101000000 VALUES LESS THAN ('2027-01-01 00:00:00') ENGINE = InnoDB, 
      PARTITION _p20280101000000 VALUES LESS THAN ('2028-01-01 00:00:00') ENGINE = InnoDB) */
      1 row in set (0.03 sec)

      The table now has only three partitions.

    3. You can query the mysql.dlm_progress table to view the execution history of the DLM policy. For more information about the dlm_progress table, see Table structures. Run the following command to query the mysql.dlm_progress table:

      mysql> SELECT * FROM mysql.dlm_progress\G

      Sample output:

      *************************** 1. row ***************************
                        Id: 1
              Table_schema: test
                Table_name: sales
               Policy_name: test_policy
               Policy_type: TABLE
            Archive_option: PARTITIONS OVER 3
            Storage_engine: CSV
             Storage_media: OSS
           Data_compressed: OFF
      Compressed_algorithm: NULL
        Archive_partitions: p20200101000000, p20210101000000, p20220101000000, _p20230101000000, _p20240101000000, _p20250101000000
             Archive_stage: ARCHIVE_COMPLETE
        Archive_percentage: 0
        Archived_file_info: null
                Start_time: 2024-07-26 17:56:20
                  End_time: 2024-07-26 17:56:50
                Extra_info: null
      1 row in set (0.00 sec)

      The partitions that store infrequently accessed cold data, including p20200101000000, p20210101000000, p20220101000000, _p20230101000000, _p20240101000000, and _p20250101000000, have been archived to the OSS foreign table.

    4. Run the following command to view the structure of the OSS foreign table:

      mysql> SHOW CREATE TABLE sales_history\G

      Sample output:

      *************************** 1. row ***************************
             Table: sales_history
      Create Table: CREATE TABLE `sales_history` (
        `id` int(11) DEFAULT NULL,
        `name` varchar(20) DEFAULT NULL,
        `order_time` datetime DEFAULT NULL,
         PRIMARY KEY (`order_time`)
      ) /*!99990 800020213 STORAGE OSS */ ENGINE=CSV DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci /*!99990 800020204 NULL_MARKER='NULL' */ /*!99990 800020223 OSS META=1 */ /*!99990 800020224 OSS_FILE_FILTER='id,name:bloom,order_time' */
      1 row in set (0.15 sec)

      The table is now a CSV table that uses the OSS engine for storage. You can query it in the same way as a local table. The specified columns have been added to the OSS_FILE_FILTER. Because order_time is a partition key, an OSS_FILE_FILTER is also created for it automatically.

    5. Query the data on the sales and sales_history tables separately.

      SELECT COUNT(*) FROM sales;
      +----------+
      | count(*) |
      +----------+
      |      984 |
      +----------+
      1 row in set (0.01 sec)
      
      SELECT COUNT(*) FROM sales_history;
      +----------+
      | count(*) |
      +----------+
      |     2016 |
      +----------+
      1 row in set (0.57 sec)           

      The total number of rows is 3,000, which matches the number of rows that were initially inserted into the sales table.

    6. Query the OSS foreign table by using the OSS_FILE_FILTER. The OSS_FILE_FILTER switch must be enabled.

      mysql> explain select * from sales_history where id = 9;
      +----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-----------------------------------------------------------------------------+
      | id | select_type | table         | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                                                       |
      +----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-----------------------------------------------------------------------------+
      |  1 | SIMPLE      | sales_history | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 2016 |    10.00 | Using where; With pushed engine condition (`test`.`sales_history`.`id` = 9) |
      +----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-----------------------------------------------------------------------------+
      1 row in set, 1 warning (0.59 sec)
      
      mysql>  select * from sales_history where id = 9;
      +------+----------------+---------------------+
      | id   | name           | order_time          |
      +------+----------------+---------------------+
      |    9 | 2531826@stiven | 2019-07-04 00:00:00 |
      +------+----------------+---------------------+
      1 row in set (0.19 sec)

Archive partitions to OSS

  1. Create a DLM policy

    The following example creates a partitioned table named sales that uses the order_time column as the partition key. The table has an INTERVAL policy and a DLM policy:

    • INTERVAL policy: When inserted data falls outside the existing partition range, a new partition is automatically created with a time interval of one year.

    • DLM policy: The table is defined to retain only three partitions. When the number of partitions exceeds three, the DLM policy is triggered and archives the older partitions directly to OSS.

    1. Create the sales table.

      CREATE TABLE `sales` (
        `id` int DEFAULT NULL,
        `name` varchar(20) DEFAULT NULL,
        `order_time` datetime NOT NULL,
         PRIMARY KEY (`order_time`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
      PARTITION BY RANGE  COLUMNS(order_time) INTERVAL(YEAR, 1)
      (PARTITION p20200101000000 VALUES LESS THAN ('2020-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION p20210101000000 VALUES LESS THAN ('2021-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION p20220101000000 VALUES LESS THAN ('2022-01-01 00:00:00') ENGINE = InnoDB)
      DLM ADD POLICY policy_part2part TIER TO PARTITION ENGINE=CSV STORAGE=OSS READ ONLY ON (PARTITIONS OVER 3);

      The DLM policy for the table is named policy_part2part. When the number of partitions exceeds three, the older partitions are archived to OSS.

    2. View the DLM policy in the mysql.dlm_policies table.

      SELECT * FROM mysql.dlm_policies\G

      Sample output:

      *************************** 1. row ***************************
                         Id: 2
               Table_schema: test
                 Table_name: sales
                Policy_name: policy_part2part
                Policy_type: PARTITION
               Archive_type: PARTITION COUNT
               Storage_mode: READ ONLY
             Storage_engine: CSV
              Storage_media: OSS
        Storage_schema_name: NULL
         Storage_table_name: NULL
            Data_compressed: OFF
       Compressed_algorithm: NULL
                    Enabled: ENABLED
            Priority_number: 10300
      Tier_partition_number: 3
             Tier_condition: NULL
                 Extra_info: null
                    Comment: NULL
      1 row in set (0.03 sec)
    3. Use the proc_batch_insert stored procedure to insert test data into the sales partitioned table. This action triggers the INTERVAL policy, which automatically creates new partitions.

      CALL proc_batch_insert(1, 3000, 'sales');

      The following result indicates that the data is inserted successfully:

      Query OK, 1 row affected, 1 warning (0.99 sec)
    4. Run the following command to view the sales table structure:

      SHOW CREATE TABLE sales \G

      Sample output:

      *************************** 1. row ***************************
             Table: sales
      Create Table: CREATE TABLE `sales` (
        `id` int(11) DEFAULT NULL,
        `name` varchar(20) DEFAULT NULL,
        `order_time` datetime DEFAULT NULL,
         PRIMARY KEY (`order_time`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
      /*!50500 PARTITION BY RANGE  COLUMNS(order_time) */ /*!99990 800020200 INTERVAL(YEAR, 1) */
      /*!50500 (PARTITION p20200101000000 VALUES LESS THAN ('2020-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION p20210101000000 VALUES LESS THAN ('2021-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION p20220101000000 VALUES LESS THAN ('2022-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20230101000000 VALUES LESS THAN ('2023-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20240101000000 VALUES LESS THAN ('2024-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20250101000000 VALUES LESS THAN ('2025-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20260101000000 VALUES LESS THAN ('2026-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20270101000000 VALUES LESS THAN ('2027-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20280101000000 VALUES LESS THAN ('2028-01-01 00:00:00') ENGINE = InnoDB) */
      1 row in set (0.03 sec)
  2. Execute the DLM policy

    1. Run the following command to execute the DLM policy:

      CALL dbms_dlm.execute_all_dlm_policies();
    2. Query the mysql.dlm_progress table to view the DLM execution history.

      SELECT * FROM mysql.dlm_progress \G

      Sample output:

      *************************** 1. row ***************************
                        Id: 4
              Table_schema: test
                Table_name: sales
               Policy_name: policy_part2part
               Policy_type: PARTITION
            Archive_option: PARTITIONS OVER 3
            Storage_engine: CSV
             Storage_media: OSS
           Data_compressed: OFF
      Compressed_algorithm: NULL
        Archive_partitions: p20200101000000, p20210101000000, p20220101000000, _p20230101000000, _p20240101000000, _p20250101000000
             Archive_stage: ARCHIVE_COMPLETE
        Archive_percentage: 100
        Archived_file_info: null
                Start_time: 2023-09-11 18:04:39
                  End_time: 2023-09-11 18:04:40
                Extra_info: null
      1 row in set (0.02 sec)
    3. Run the following command to view the sales table structure:

      SHOW CREATE TABLE sales \G

      Sample output:

      *************************** 1. row ***************************
             Table: sales
      Create Table: CREATE TABLE `sales` (
        `id` int(11) DEFAULT NULL,
        `name` varchar(20) DEFAULT NULL,
        `order_time` datetime DEFAULT NULL,
         PRIMARY KEY (`order_time`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci CONNECTION='default_oss_server'
      /*!99990 800020205 PARTITION BY RANGE  COLUMNS(order_time) */ /*!99990 800020200 INTERVAL(YEAR, 1) */
      /*!99990 800020205 (PARTITION p20200101000000 VALUES LESS THAN ('2020-01-01 00:00:00') ENGINE = CSV,
       PARTITION p20210101000000 VALUES LESS THAN ('2021-01-01 00:00:00') ENGINE = CSV,
       PARTITION p20220101000000 VALUES LESS THAN ('2022-01-01 00:00:00') ENGINE = CSV,
       PARTITION _p20230101000000 VALUES LESS THAN ('2023-01-01 00:00:00') ENGINE = CSV,
       PARTITION _p20240101000000 VALUES LESS THAN ('2024-01-01 00:00:00') ENGINE = CSV,
       PARTITION _p20250101000000 VALUES LESS THAN ('2025-01-01 00:00:00') ENGINE = CSV,
       PARTITION _p20260101000000 VALUES LESS THAN ('2026-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20270101000000 VALUES LESS THAN ('2027-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20280101000000 VALUES LESS THAN ('2028-01-01 00:00:00') ENGINE = InnoDB) */
      1 row in set (0.03 sec)

      The output shows that the partitions p20200101000000, p20210101000000, p20220101000000, _p20230101000000, _p20240101000000, and _p20250101000000 of the sales partitioned table are archived to OSS. Only the three hot data partitions, _p20260101000000, _p20270101000000, and _p20280101000000, are retained in the InnoDB engine. The sales table is now a hybrid partitioned table. For information about how to query data in a hybrid partitioned table, see Query a hybrid partitioned table.

Delete cold data

  1. Create a DLM policy

    The following example creates a partitioned table named sales that uses the order_time column as the partition key. The table has an INTERVAL policy and a DLM policy:

    • INTERVAL policy: When inserted data falls outside the existing partition range, a new partition is automatically created with a time interval of one year.

    • DLM policy: The table is defined to retain only three partitions. When the number of partitions exceeds three, the DLM policy is triggered to delete the cold data.

    1. Create the sales table with a DLM policy.

      CREATE TABLE `sales` (
        `id` int DEFAULT NULL,
        `name` varchar(20) DEFAULT NULL,
        `order_time` datetime DEFAULT NULL,
         PRIMARY KEY (`order_time`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
      PARTITION BY RANGE  COLUMNS(order_time) INTERVAL(YEAR, 1)
      (PARTITION p20200101000000 VALUES LESS THAN ('2020-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION p20210101000000 VALUES LESS THAN ('2021-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION p20220101000000 VALUES LESS THAN ('2022-01-01 00:00:00') ENGINE = InnoDB)
      DLM ADD POLICY test_policy TIER TO NONE ON (PARTITIONS OVER 3);

      The DLM policy for the table is named test_policy. It is triggered when the number of partitions exceeds three. When executed, the policy deletes the cold data.

    2. Run the following command to query the mysql.dlm_policies table:

      SELECT * FROM mysql.dlm_policies\G

      Sample output:

      *************************** 1. row ***************************
                         Id: 4
               Table_schema: test
                 Table_name: sales
                Policy_name: test_policy
                Policy_type: NONE
               Archive_type: PARTITION COUNT
               Storage_mode: NULL
             Storage_engine: NULL
              Storage_media: NULL
        Storage_schema_name: NULL
         Storage_table_name: NULL
            Data_compressed: OFF
       Compressed_algorithm: NULL
                    Enabled: ENABLED
            Priority_number: 50000
      Tier_partition_number: 3
             Tier_condition: NULL
                 Extra_info: null
                    Comment: NULL
      1 row in set (0.01 sec)
    3. Use the proc_batch_insert stored procedure to insert test data into the sales partitioned table. This action triggers the INTERVAL policy, which automatically creates new partitions.

      CALL proc_batch_insert(1, 3000, 'sales');
      Query OK, 1 row affected, 1 warning (0.99 sec)
    4. Run the following command to view the sales table structure:

      SHOW CREATE TABLE sales \G

      Sample output:

      *************************** 1. row ***************************
             Table: sales
      Create Table: CREATE TABLE `sales` (
        `id` int(11) DEFAULT NULL,
        `name` varchar(20) DEFAULT NULL,
        `order_time` datetime DEFAULT NULL,
         PRIMARY KEY (`order_time`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
      /*!50500 PARTITION BY RANGE  COLUMNS(order_time) */ /*!99990 800020200 INTERVAL(YEAR, 1) */
      /*!50500 (PARTITION p20200101000000 VALUES LESS THAN ('2020-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION p20210101000000 VALUES LESS THAN ('2021-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION p20220101000000 VALUES LESS THAN ('2022-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20230101000000 VALUES LESS THAN ('2023-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20240101000000 VALUES LESS THAN ('2024-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20250101000000 VALUES LESS THAN ('2025-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20260101000000 VALUES LESS THAN ('2026-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20270101000000 VALUES LESS THAN ('2027-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20280101000000 VALUES LESS THAN ('2028-01-01 00:00:00') ENGINE = InnoDB) */
      1 row in set (0.03 sec)
  2. Execute the DLM policy

    1. Run the following command to execute the DLM policy directly:

      CALL dbms_dlm.execute_all_dlm_policies();
    2. While the DLM policy is running, query the data in the mysql.dlm_progress table.

      SELECT * FROM mysql.dlm_progress \G

      The results in the table are as follows:

      *************************** 1. row ***************************
                        Id: 1
              Table_schema: test
                Table_name: sales
               Policy_name: test_policy
               Policy_type: NONE
            Archive_option: PARTITIONS OVER 3
            Storage_engine: NULL
             Storage_media: NULL
           Data_compressed: OFF
      Compressed_algorithm: NULL
        Archive_partitions: p20200101000000, p20210101000000, p20220101000000, _p20230101000000, _p20240101000000, _p20250101000000
             Archive_stage: ARCHIVE_COMPLETE
        Archive_percentage: 100
        Archived_file_info: null
                Start_time: 2023-01-09 17:31:24
                  End_time: 2023-01-09 17:31:24
                Extra_info: null
      1 row in set (0.03 sec)

      The partitions that store infrequently accessed cold data, including p20200101000000, p20210101000000, p20220101000000, _p20230101000000, _p20240101000000, and _p20250101000000, have been deleted.

    3. The sales table structure is now as follows:

      SHOW CREATE TABLE sales \G

      Sample output:

      *************************** 1. row ***************************
             Table: sales
      Create Table: CREATE TABLE `sales` (
        `id` int(11) DEFAULT NULL,
        `name` varchar(20) DEFAULT NULL,
        `order_time` datetime DEFAULT NULL,
         PRIMARY KEY (`order_time`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
      /*!50500 PARTITION BY RANGE  COLUMNS(order_time) */ /*!99990 800020200 INTERVAL(YEAR, 1) */
      /*!50500 (PARTITION _p20260101000000 VALUES LESS THAN ('2026-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20270101000000 VALUES LESS THAN ('2027-01-01 00:00:00') ENGINE = InnoDB,
       PARTITION _p20280101000000 VALUES LESS THAN ('2028-01-01 00:00:00') ENGINE = InnoDB) */
      1 row in set (0.02 sec)

Manage policies with ALTER TABLE

  • Create a DLM policy by using the ALTER TABLE statement.

    ALTER TABLE t DLM ADD POLICY test_policy TIER TO TABLE ENGINE=CSV STORAGE=OSS READ ONLY
    STORAGE TABLE_NAME = 'sales_history' ON (PARTITIONS OVER 3);

    The DLM policy for table t is named test_policy. It is triggered when the number of partitions exceeds three. When executed, this policy archives data from the oldest partitions of table t to an OSS table named sales_history.

  • Enable the test_policy DLM policy on table t.

    ALTER TABLE t DLM ENABLE POLICY test_policy;
  • Disable the test_policy DLM policy on table t.

    ALTER TABLE t DLM DISABLE POLICY test_policy;
  • Delete the test_policy DLM policy from table t.

    ALTER TABLE t DLM DROP POLICY test_policy;

Troubleshoot execution errors

DLM policies may fail to execute due to configuration issues. Error records are stored in the mysql.dlm_progress table. Run the following command to view error records:

SELECT * FROM mysql.dlm_progress WHERE Archive_stage = "ARCHIVE_ERROR";

Find the error details in the Extra_info field. After you identify and resolve the cause of the error, either delete the record or update its Archive_stage to ARCHIVE_COMPLETE. You can then run the call dbms_dlm.execute_all_dlm_policies; command to manually execute the policy, or wait for the next scheduled execution.

Note

For data security, if a policy execution record has the ARCHIVE_ERROR state, the scheduler will not run the policy again automatically. After you confirm the cause of the failure and update the record, the policy resumes its scheduled execution.