Logical partition tables give you automatic partition lifecycle management: Hologres creates partitions when data arrives and removes them when the partition becomes empty. The parent table is a physical table; each partition is a logical concept, not a separate physical object.
Use logical partition tables when:
Your dataset is large and time-series or category-based (daily logs, event streams, tenant data).
You want Hologres to manage partition creation and cleanup automatically, without DDL overhead.
You want per-partition expiration, hot/cold tiering, or selective Binlog generation.
Prefer physical partition tables when you frequently replace entire partitions with TRUNCATE or INSERT OVERWRITE—those operations are faster on physical partitions because they avoid large-scale deletes.
Logical partition tables require Hologres 3.1 or later.
Limitations
Only
LISTpartitioning is supported.RANGEandHASHare not supported.A partition key can include one or two columns.
Supported partition key data types:
INT,TEXT,VARCHAR,DATE,TIMESTAMP, andTIMESTAMPTZ.Partition keys must be
NOT NULL.The partition key of a logical partition table supports generated columns.
A single logical partition table supports up to 5,200 partitions. A database supports up to 200,000 logical partitions total.
Batch import limits
| Scenario | Threshold | Behavior |
|---|---|---|
| Single batch import job | > 50 partitions | Error: Bulkload partition count exceed limit, partition count is xxx, limit is xxx |
| Fixed Plan concurrent writes (per table) | > 30 partitions | Throttled — Hologres waits several seconds, then auto-submits |
| Fixed Plan concurrent writes (per table) | > 100 partitions | Error: mem partition count exceed reject limit |
Unpersisted partition limits (per worker node)
An unpersisted partition is one written to memory but not yet flushed to disk. The count is calculated as: user partitions × shard count × index count per table. Shard count includes replica shards.
| Threshold | Behavior |
|---|---|
| > 500 unpersisted partitions | Throttled — Hologres waits several seconds, then auto-submits |
| > 5,000 unpersisted partitions | Error: mem partition count exceed reject limit |
Usage notes
Partition granularity: Avoid partitions with fewer than 100 million rows. Fine-grained partitions reduce query acceleration benefits and increase the risk of small file accumulation. For example, partitioning by day is reasonable for high-volume workloads; partitioning by client ID or sub-hour intervals is usually too fine.
Write pattern: Write data to partitions sequentially. Avoid writing to many partitions simultaneously.
Data quality: Keep incoming data clean. Dirty data—such as timestamps that don't fall at midnight when using daily partitions—can cause unexpected partition growth.
Partition lifecycle: Do not manually create or delete partitions. Partitions exist only when they contain data. When all data in a partition is deleted, Hologres removes the partition asynchronously.
TRUNCATE and Binlog: TRUNCATE does not generate Binlog. To disable Binlog generation for a session, run
SET hg_experimental_generate_binlog = offbefore TRUNCATE.Table property changes: To modify table properties on a logical partition table, use the REBUILD syntax. The backend automatically splits the task and executes it sequentially by partition. For resharding operations (for example, moving the table to a different Table Group), do not use the
HG_MOVE_TABLE_TO_TABLE_GROUPstored procedure. See the Table Group and Shard Count Operation Guide for the correct approach.
Create a logical partition table
Syntax
-- Create a logical partition parent table
CREATE TABLE [IF NOT EXISTS] [<schema_name>.]<table_name> ([
{
<column_name> <column_type> [ <column_constraints>, [...]]
| <table_constraints>
[, ...]
}
])
LOGICAL PARTITION BY LIST(<partition_column_1> [, <partition_column_2>])
[WITH(
<property_name> = <property_value>
[, ...]
)];Partitions are created and removed automatically based on data. Do not manually create or delete partitions.
Parameters
| Parameter | Description |
|---|---|
schema_name | The schema that contains the table. Omit if the parent and child tables are in the same schema. |
table_name | The name of the parent partition table. |
column_name | The name of a column. |
column_type | The data type of the column. |
column_constraints | Column-level constraints. |
table_constraints | Table-level constraints. |
partition_column | The partition key. Specify one or two columns. |
property_name | The name of a table property. |
property_value | The value to assign to the table property. |
Table properties
These properties are set on the parent table and apply to all partitions. Because the parent table is a physical table and partitions are logical concepts, you cannot set these properties on individual partitions directly.
| Property | Default | Valid values | Notes |
|---|---|---|---|
partition_expiration_time | None (no auto-cleanup) | '30 day', '12 month', etc. | Applies only to tables with a single, time-based partition key. Use the same time unit as your partition key. |
partition_keep_hot_window | All data stays hot | '30 day', '12 month', etc. | Applies only to tables with a single, time-based partition key. Data outside this window is moved to cold storage asynchronously. See Data tiering storage. |
partition_require_filter | FALSE | TRUE, FALSE | If TRUE, queries on the parent table must include a partition filter condition. Queries without one fail. |
binlog_level | 'none' | 'none', 'replica' | Enables or disables Binlog for the parent table. See Subscribe to Hologres binary logging. |
binlog_ttl | 2592000 (30 days, in seconds) | Integer (seconds) | The time-to-live (TTL) for Binlog data. |
partition_generate_binlog_window | None (all data generates Binlog) | '3 day', '12 hour', etc. | Only data in partitions created within the window generates Binlog. Applies only to tables with a single, time-based partition key. |
Other properties (indexes, orientation, etc.) | — | — | Logical partition tables support distribution_key, clustering_key, orientation, time_to_live_in_seconds, and other standard properties. See CREATE TABLE and the Scenario-based table creation optimization guide. Dynamic partition management properties from physical partition tables are not supported. See Dynamic partition management. |
Partition properties
These properties apply to individual partitions. Modify them with ALTER LOGICAL PARTITION TABLE.
| Property | Default | Valid values | Behavior |
|---|---|---|---|
keep_alive | FALSE | TRUE, FALSE | If TRUE, the partition is never cleaned up automatically, even if partition_expiration_time is set on the parent table. |
storage_mode | Not set (follows parent's partition_keep_hot_window) | 'hot', 'cold' | Overrides the parent table's partition_keep_hot_window for this partition. |
generate_binlog | Not set (follows parent's partition_generate_binlog_window) | 'on', 'off' | Overrides the parent table's partition_generate_binlog_window for this partition. |
Examples
Example 1: Regular column as partition key
CREATE TABLE public.hologres_logical_parent_1 (
a TEXT,
b INT,
c TIMESTAMP,
ds DATE NOT NULL,
PRIMARY KEY (b, ds))
LOGICAL PARTITION BY LIST (ds)
WITH (
orientation = 'column',
distribution_key = 'b',
partition_expiration_time = '30 day',
partition_keep_hot_window = '15 day',
partition_require_filter = TRUE,
binlog_level = 'replica',
partition_generate_binlog_window = '3 day'
);Example 2: Generated column as partition key
The partition key ds is derived from the c column using date_trunc. This automatically assigns each row to the correct daily partition without requiring the caller to compute the partition value. For more information, see Hologres generated columns.
CREATE TABLE public.hologres_logical_parent_2 (
a TEXT,
b INT,
c TIMESTAMP,
ds TIMESTAMP GENERATED ALWAYS AS (date_trunc('day', c)) STORED NOT NULL,
PRIMARY KEY (b, ds))
LOGICAL PARTITION BY LIST (ds)
WITH (
orientation = 'column',
distribution_key = 'b',
partition_expiration_time = '30 day',
partition_keep_hot_window = '15 day',
partition_require_filter = TRUE,
binlog_level = 'replica',
partition_generate_binlog_window = '3 day'
);Example 3: Two columns as partition keys
CREATE TABLE public.hologres_logical_parent_3 (
a TEXT,
b INT,
yy TEXT NOT NULL,
mm TEXT NOT NULL)
LOGICAL PARTITION BY LIST (yy, mm)
WITH (
orientation = 'column',
distribution_key = 'b',
partition_require_filter = TRUE
);Manage data
Lock granularity
| Operation | Lock type | Notes |
|---|---|---|
| Batch import or update for a specified partition; TRUNCATE for a specified partition | Partition lock | Other partitions remain unaffected. |
| Batch import or update without specifying a partition; TRUNCATE without specifying a partition; any DELETE | Table lock | Other data management operations wait until the lock is released. |
| Fixed Plan write, update, or delete | Row lock | Conflicts with batch import, update, or delete. Does not conflict with other Fixed Plan operations. |
Choose a data cleanup method
| Method | When to use | Lock type | Notes |
|---|---|---|---|
DELETE | Selectively delete rows matching a condition | Table lock | Slower for large datasets |
TRUNCATE (partition-level) | Remove all data in one or more specific partitions | Partition lock | Faster than DELETE; does not generate Binlog; not supported in compute group DML — use the leader compute group |
TRUNCATE (table-level) | Remove all data in the parent table | Table lock | Fastest for full cleanup; does not generate Binlog |
INSERT OVERWRITE | Replace all data in a partition with new data | Partition lock (per partition) | Synchronous; if multiple partitions are specified, they are processed in parallel — split into sequential tasks to reduce CPU and memory usage |
Write to the parent table
Data write, update, and cleanup operations work the same as for standard tables. Hologres automatically creates or removes partitions based on data.
-- Write data; Hologres creates partitions automatically
INSERT INTO public.hologres_logical_parent_2
VALUES
('a', 1, '2025-03-16 10:00:00'),
('b', 2, '2025-03-17 11:00:00'),
('c', 3, '2025-03-18 12:00:00'),
('d', 4, '2025-03-19 13:00:00'),
('e', 5, '2025-03-20 14:00:00');-- Delete rows (table lock)
DELETE FROM public.hologres_logical_parent_2 WHERE ds = '2025-03-20';-- Truncate the entire parent table (no Binlog generated)
SET hg_experimental_generate_binlog = off;
TRUNCATE public.hologres_logical_parent_2;Write to a specific partition
-- Import into a specified partition
INSERT INTO public.hologres_logical_parent_1
PARTITION (ds = '2025-03-16')
VALUES
('a', 1, '2025-03-16 10:00:00', '2025-03-16');-- Rows that don't match the specified partition are silently skipped (no error)
INSERT INTO public.hologres_logical_parent_1
PARTITION (ds = '2025-03-16')
VALUES
('a', 1, '2025-03-16 10:00:00', '2025-03-16'),
('b', 2, '2025-03-17 11:00:00', '2025-03-17');Clean up partition data
-- Delete rows from specific partitions (table lock)
DELETE FROM public.hologres_logical_parent_1 WHERE ds = '2025-03-16' or ds = '2025-03-17';-- Truncate specific partitions (partition lock, no Binlog generated)
-- Not supported in compute group DML; run in the leader compute group.
SET hg_experimental_generate_binlog = off;
TRUNCATE public.hologres_logical_parent_1 PARTITION (ds = '2025-03-16') PARTITION (ds = '2025-03-17');Overwrite a partition
Hologres 3.1 and later support the native INSERT OVERWRITE syntax for logical partition tables. See INSERT OVERWRITE.
INSERT OVERWRITE is synchronous. If you specify multiple logical partitions, Hologres processes them in parallel, which increases CPU and memory usage. Split multi-partition overwrites into sequential tasks.
Query logical partition tables
-- Query with a partition filter condition
SELECT * FROM public.hologres_logical_parent_1 WHERE ds = '2025-03-16';-- Query without a partition filter condition
-- Requires partition_require_filter = FALSE on the parent table
SELECT * FROM public.hologres_logical_parent_1;If partition_require_filter is set to TRUE, queries without a partition filter condition fail.
View metadata
Hologres provides system tables and functions to query metadata for logical partition tables.
| Object | Purpose |
|---|---|
hologres.hg_table_properties | View table properties |
hologres.hg_list_logical_partition('<table_name>') | List all partitions in a logical partition table |
hologres.hg_logical_partitioned_table_properties | List all logical partitions and their properties in the current instance |
hologres.hg_partition_file_status('<table_name>') | Query hot and cold storage sizes and file counts for all partitions (Hologres 3.1.4 and later) |
Check whether a table is a logical partition table:
SELECT *
FROM hologres.hg_table_properties
WHERE
table_name = '<table_name>'
AND property_key = 'is_logical_partitioned_table'
AND property_value = 'true';List all partitions:
SELECT * FROM hologres.hg_list_logical_partition('<schema_name>.<table_name>');List partition property configurations:
This query returns only configurations that differ between child partitions and the parent table. An empty result means no partition-level overrides are set.
SELECT *
FROM hologres.hg_logical_partitioned_table_properties
WHERE
table_namespace = '<schema_name>'
AND table_name = '<table_name>'
ORDER BY partition DESC;View hot and cold storage sizes:
SELECT * FROM hologres.hg_partition_file_status('<schema_name>.<table_name>');Logical partitions are also compatible with standard Hologres system tables.
View the DDL for a logical partition table:
SELECT hg_dump_script('<schema_name>.<table_name>');View parent table properties:
SELECT *
FROM hologres.hg_table_properties
WHERE
table_namespace = '<schema_name>'
AND table_name = '<table_name>';View the largest partition:
Because data cleanup and partition cleanup are asynchronous, MAX_PT may return incorrect results if the largest partition has been emptied. Use INSERT OVERWRITE to delete data to avoid this issue.SELECT MAX_PT('<schema_name>.<table_name>');Check whether any partition table exceeds the partition limit:
CREATE OR REPLACE PROCEDURE check_logical_partition_count()
LANGUAGE 'plpgsql'
AS $$
DECLARE
table_max_partition_count bigint;
table_partition_count bigint;
exceeded_logical_partition_limit boolean;
row_record record;
BEGIN
SELECT substring(result FROM '^[^:]*: (\d+)')::INTEGER INTO table_max_partition_count
FROM hg_admin_command('get_global_flag', 'flag=table_max_partition_count') AS result;
RAISE NOTICE 'table_max_partition_count=%', table_max_partition_count;
FOR row_record IN
SELECT table_namespace, table_name
FROM hologres.hg_table_properties
WHERE property_key = 'is_logical_partitioned_table' AND (property_value = 'true' OR property_value = 't')
LOOP
SELECT count(*) INTO table_partition_count
FROM hologres.hg_list_logical_partition(quote_ident(row_record.table_namespace) || '.' || quote_ident(row_record.table_name));
IF table_partition_count > table_max_partition_count THEN
RAISE NOTICE 'table %.% partition count exceeds limit (% > %)', row_record.table_namespace, row_record.table_name, table_partition_count, table_max_partition_count;
END IF;
END LOOP;
END;
$$;
CALL check_logical_partition_count();