All Products
Search
Document Center

Hologres:Migrate from physical to logical partitioned tables

Last Updated:Mar 26, 2026

Physical partitioned tables can develop two stability problems at scale: metadata bloat when a table group exceeds 10,000 child tables, 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 partitioned tables, causing large metadata scale.

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

Choose a migration approach

ApproachWhen to useDowntimeRisk
Dual-write verification (recommended)Any migration where business continuity mattersMinimal — old and new tables run in parallelLow
REBUILD (not recommended)Acceptable to have a longer change window and allow some read/write failuresLonger — write tasks stop during migrationHigh — 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 the logical partitioned table and copy existing data

Choose one of the following methods based on your situation.

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');

Manual migration (for schema changes or large data volumes)

Manual migration lets you optimize table properties 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 structure 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 structure 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 parent table via Fixed Plan: no changes needed.

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

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

  • 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: 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: logical partitioned table
INSERT INTO user_profile_lp_1 SELECT a, b, ds FROM <source_table> WHERE ds = '202505';

Scenario 2: Refresh data in a partition

Note

If the original task uses hg_insert_overwrite to refresh multiple child tables at once, split the refreshes by partition and run them serially after migrating to a logical partitioned table. Use the native INSERT OVERWRITE syntax instead. For more information, see INSERT OVERWRITE.

-- 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.

OperationPhysical partitioned tableLogical partitioned table
Query parent table DDLhg_dump_script functionNo difference
Query parent table propertieshologres.hg_table_propertiesNo difference
Query partition listQuery all child tableshologres.hg_list_logical_partition
Query partition propertieshologres.hg_table_propertieshologres.hg_logical_partitioned_table_properties
Query parent table storagehg_table_storage_statushg_partition_file_status

Property and parameter mapping

The following table maps dynamic partition management parameters and other table properties between physical and logical partitioned tables.

Note

If the original physical partitioned table uses a non-time type field (such as TEXT) as the partition key and uses dynamic partition management, partition_expiration_time and partition_keep_hot_window are not supported on the logical partitioned table.

ModuleFeaturePhysical partitioned tableLogical partitioned table
Dynamic partition managementEnableauto_partitioning_enableNo equivalent parameter
Time unitauto_partitioning_time_unitNo separate configuration; only time-type partitions are supported
Time zoneauto_partitioning_time_zoneNo equivalent parameter
Pre-created partitionsauto_partitioning_num_precreateNo equivalent parameter
Historical partitions to retainauto_partitioning_num_retentionpartition_expiration_time
Hot partitions to retainauto_partitioning_num_hotpartition_keep_hot_window
Scheduling timeauto_partitioning_schd_start_timeNo equivalent parameter
Child table date/time formatauto_partitioning_time_formatNo equivalent parameter
Partition managementRetain partitionkeep_alivekeep_alive
Hot/cold storagestorage_modestorage_mode
Binary logSwitch (parent table)binlog_levelbinlog_level
Lifecycle (parent table)binlog_ttlbinlog_ttl
Dynamic binary log by partitionNot supportedpartition_generate_binlog_window
Switch (partitions)Inherits from parent; modification not supportedgenerate_binlog
Lifecycle (partitions)Child tables support modificationInherits from parent; modification not supported
Indexes and table propertiesbitmap_columnsChild tables support modificationInherits from parent; modification not supported
dictionary_encoding_columnsChild tables support modificationInherits from parent; modification not supported
orientation, table_group, and other propertiesInherits from parent; modification not supportedInherits from parent; modification not supported
Primary key, distribution_key, clustering_key, and other indexesInherits from parent; modification not supportedInherits from parent; modification not supported