All Products
Search
Document Center

Hologres:Migrate from physical to logical partitioned tables

Last Updated:Jun 03, 2026

Physical partitioned tables can develop two stability problems at scale: metadata bloat when a table group exceeds 10,000 child tables (partitions), and performance degradation from high-frequency DDL operations when new partitions are added daily. Hologres V3.1 introduces logical partitioned tables to address both issues. This topic describes how to migrate an existing physical partitioned table to a logical partitioned table.

When to migrate

Migrate to a logical partitioned table if your physical partitioned table meets either of the following conditions:

  • A table group contains more than 10,000 child tables, causing large metadata scale.

  • New partitions are added daily, resulting in frequent DDL operations.

Choose a migration approach

Approach

When to use

Downtime

Risk

Dual-write verification (recommended)

Any migration where business continuity matters

Minimal — old and new tables run in parallel

Low

REBUILD (not recommended)

Acceptable to have a longer change window and allow some read/write failures

Longer — write tasks stop during migration

High — tasks may fail before adaptation is complete

Migrate using dual-write verification (recommended)

This approach keeps the old and new tables running in parallel during migration, minimizing business impact.

Overview

  1. Stop write tasks for the physical partitioned table, create a new logical partitioned table, and copy existing data.

  2. Create a write task for the new table and enable dual writing to both tables.

  3. Verify the new logical partitioned table.

  4. Switch business queries and write tasks to the new table.

  5. Adapt O&M tasks to the new table.

Step 1: Create a logical partitioned table and load existing data

Choose one of the following methods based on your situation.

Method 1: CLONE (recommended for moderate data volumes with no schema changes)

hg_clone_to_logical_partition automatically creates a new logical partitioned table and copies all data from the original table. The original physical partitioned table is not deleted.

Important

Stop real-time write tasks before running CLONE. After CLONE completes, create new write tasks that write to both the old and new tables simultaneously to keep data in sync. After migration is complete, thoroughly verify both tables, complete the adaptation of import tasks, query tasks, and O&M tasks, and then clean up the original physical partitioned table.

CALL hg_clone_to_logical_partition('user_profile', 'user_profile_logical');

For large data volumes, run CLONE asynchronously to avoid timeout. After submitting, use the returned query_id to check progress in Get query insights.

SET statement_timeout = 0;
ASYNC CALL hg_clone_to_logical_partition('user_profile', 'user_profile_logical');

Method 2: Manual migration (for schema changes or large data volumes)

Manual migration lets you optimize table schema and control the migration pace.

Important

Stop real-time write tasks before importing data. After import completes, create new write tasks that write to both tables simultaneously. After migration is complete, thoroughly verify both tables, complete the adaptation of import tasks, query tasks, and O&M tasks, and then clean up the original physical partitioned table.

  1. Create the logical partitioned table. See Table schema conversion for DDL changes required.

  2. Import historical data using hg_insert_overwrite:

    CALL hg_insert_overwrite('logical_partition_table', '{20250601, 20250602}'::text[], 'SELECT * FROM tb');

Step 2: Enable dual writing

Create a new write task for the logical partitioned table and run it alongside the existing write task for the physical partitioned table. This ensures both tables stay in sync during the verification period.

Step 3: Verify the new table

Run your business queries against the logical partitioned table and confirm the data and behavior match the physical partitioned table.

Step 4: Switch business to the new table

Use one of the following methods:

Option A (recommended): Update the table name in query tasks to point to the new logical partitioned table and add partition filter conditions where needed.

Option B: Use RENAME to swap the table names atomically:

Warning

This operation renames existing tables. Make sure your write and query tasks are ready to target the parent table before executing.

BEGIN;
ALTER TABLE <source_table_name> RENAME TO <source_table_name_archive>;
ALTER TABLE <target_table_name> RENAME TO <source_table_name>;
COMMIT;

After switching, update write and query tasks that previously targeted child tables to use the parent table instead, and add partition filter conditions.

Step 5: Adapt O&M tasks

Update any O&M tasks that differ between physical and logical partitioned tables. See O&M task adaptation for details.

Migrate using REBUILD (not recommended)

Warning

During REBUILD migration, some read and write tasks may fail. Use this approach only if a longer change window is acceptable and brief task failures are tolerable. This method is not recommended for migrating partitioned tables.

When REBUILD completes, the physical partitioned table is renamed to tmp_rebuild_old_<query_id>_<unique_id>_<table_name>. Related tasks may generate errors until you complete task adaptation.

  1. Stop write tasks for the physical partitioned table.

  2. Run REBUILD to convert the table:

    -- Add the NOT NULL constraint to the partition field.
    ASYNC REBUILD TABLE user_profile ALTER ds SET NOT NULL;
    
    -- Convert the physical partitioned table to a logical partitioned table (retains the original).
    ASYNC REBUILD TABLE user_profile WITH (keep_source) TO logical partition;

    For more information, see REBUILD.

  3. Update write tasks and restart them.

  4. Adapt query tasks to the new logical partitioned table.

  5. Adapt O&M tasks to the new logical partitioned table.

Table schema conversion

When creating a logical partitioned table from an existing physical partitioned table DDL, make the following changes:

  • Add the LOGICAL keyword before PARTITION BY.

  • Add NOT NULL to the partition key column.

  • (Optional) Add a second partition key. Physical partitioned tables support one partition key; logical partitioned tables support up to two.

Physical partitioned table:

BEGIN;
CREATE TABLE user_profile (
    a TEXT,
    b TEXT,
    ds TEXT
)
PARTITION BY LIST (ds);
CREATE TABLE user_profile_202503 PARTITION OF user_profile FOR VALUES IN ('202503');
CREATE TABLE user_profile_202504 PARTITION OF user_profile FOR VALUES IN ('202504');
COMMIT;

Logical partitioned table — one partition key:

CREATE TABLE user_profile_lp_1 (
    a TEXT,
    b TEXT,
    ds TEXT NOT NULL)
LOGICAL PARTITION BY LIST (ds);

Logical partitioned table — two partition keys (splitting ds into yy for year and mm for month):

CREATE TABLE user_profile_lp_2 (
    a TEXT,
    b TEXT,
    yy TEXT NOT NULL,
    mm TEXT NOT NULL)
LOGICAL PARTITION BY LIST (yy, mm);

Import task adaptation

If your import task writes to the physical partitioned table via Fixed Plan: no changes needed.

If your import task writes to child tables (partitions): make the following changes:

  • Remove statements that create child tables. Logical partitioned tables have no physical partitions.

  • Change the target table name from the child table name to the parent table name.

Scenario 1: Create a child table and import data

-- Original task: import data to physical partitioned table
CREATE TABLE user_profile_202505 PARTITION OF user_profile FOR VALUES IN ('202505');
INSERT INTO user_profile_202505 SELECT a, b, ds FROM <source_table> WHERE ds = '202505';

-- Updated task: import data to logical partitioned table
INSERT INTO user_profile_lp_1 SELECT a, b, ds FROM <source_table> WHERE ds = '202505';

Scenario 2: Insert overwrite a partition

Note

If the original task uses hg_insert_overwrite to overwrite multiple partitions at once, split the overwrites by partition, run them serially, and use the native INSERT OVERWRITE syntax after migrating to a logical partitioned table.

-- Original: physical partitioned table (temporary table method)
CREATE TABLE tmp_user_profile_202505(a text, b text, ds text);
INSERT INTO tmp_user_profile_202505 SELECT a, b, ds FROM <source_table> WHERE ds = '202505';

BEGIN;
DROP TABLE IF EXISTS user_profile_202505;
ALTER TABLE tmp_user_profile_202505 RENAME TO user_profile_202505;
ALTER TABLE user_profile ATTACH PARTITION user_profile_202505 FOR VALUES IN ('202505');
COMMIT;

-- Original: physical partitioned table (hg_insert_overwrite method)
CALL hg_insert_overwrite('user_profile', '202505', $$SELECT a, b, mm FROM <source_table> WHERE ds='202505'$$);

-- Updated: logical partitioned table (native INSERT OVERWRITE)
INSERT OVERWRITE user_profile_lp_1 PARTITION (ds = '202505') SELECT a, b, ds FROM <source_table> WHERE ds='202505';

Query task adaptation

If your query targets the parent table: no changes needed.

If your query targets a child table: change it to query the parent table and add a partition filter condition.

-- Original: physical partitioned table
SELECT * FROM user_profile_202504;

-- Updated: logical partitioned table
SELECT * FROM user_profile_lp_1 WHERE ds = '202504';

O&M task adaptation

Some O&M operations use different system tables or functions for logical partitioned tables.

Operation

Physical partitioned table

Logical partitioned table

Query parent table DDL

hg_dump_script function

No difference

Query parent table properties

hologres.hg_table_properties

No difference

Query partition list

Query all child tables

hologres.hg_list_logical_partition

Query partition properties

hologres.hg_table_properties

hologres.hg_logical_partitioned_table_properties

Query parent table storage

hg_table_storage_status

hg_partition_file_status

Property and parameter mapping

The following table maps automatic partitioning parameters and other table properties between physical and logical partitioned tables.

Note

If the original physical partitioned table uses a non-time field (such as TEXT) as the partition key and uses automatic partition management, Hologres V4.2 and later supports partition_expiration_time and partition_keep_hot_window on the logical partitioned table. You must also set partition_time_format to specify the time format. Versions earlier than V4.2 do not support this configuration.

Module

Feature

Physical partitioned table

Logical partitioned table

Automatic partitioning

Enable

auto_partitioning_enable

No equivalent parameter

Time unit

auto_partitioning_time_unit

No separate configuration; only time partitions are supported

Time zone

auto_partitioning_time_zone

No equivalent parameter

Pre-created partitions

auto_partitioning_num_precreate

No equivalent parameter

Partitions to retain

auto_partitioning_num_retention

partition_expiration_time

Hot partitions to retain

auto_partitioning_num_hot

partition_keep_hot_window

Scheduling time

auto_partitioning_schd_start_time

No equivalent parameter

Partition date/time format

auto_partitioning_time_format

No equivalent parameter

Partition management

Retain partition

keep_alive

keep_alive

Hot/cold storage

storage_mode

storage_mode

Binary log

Enable (parent table)

binlog_level

binlog_level

Lifecycle (parent table)

binlog_ttl

binlog_ttl

Dynamic binary log by partition

Not supported

partition_generate_binlog_window

Enable (partitions)

Inherits from parent; modification not supported

generate_binlog

Lifecycle (partitions)

Partitions support modification

Inherits from parent; modification not supported

Indexes and table properties

bitmap_columns

Partitions support modification

Inherits from parent; modification not supported

dictionary_encoding_columns

Partitions support modification

Inherits from parent; modification not supported

orientation, table_group, and other properties

Inherits from parent; modification not supported

Inherits from parent; modification not supported

Primary key, distribution_key, clustering_key, and other indexes

Inherits from parent; modification not supported

Inherits from parent; modification not supported