Hologres V1.3 and later collect daily statistics for all tables in your instance and store them in the hologres.hg_table_info system table. Use this data to monitor storage usage, track access patterns, and identify tables that need optimization.
Limitations
Table statistics are available only in Hologres V1.3 and later. If your instance is running an earlier version, upgrade it first. For more information, see Common errors when preparing for an upgrade or join the Hologres DingTalk group. For more information, see How to get online support?.
On the day an instance is upgraded from V1.1 to V1.3, table statistics are not generated. Querying
hg_table_infoon that day returns the following error:meta warehouse store currently not available. Wait until the following day to query table statistics.
Usage notes
Statistics logs are retained for 30 days by default.
For non-partitioned internal tables (
type='TABLE'), you can query detailed statistics including storage size, file count, read count, write count, and row count.For other object types—views, materialized views, foreign tables, and parent tables—only basic information is available, such as partition count, foreign table name, and view definitions.
hg_table_infois part of the Hologres metadata warehouse and is not covered by the product's Service-Level Agreement (SLA). Failures to queryhg_table_infodo not affect your instance's business queries.
Understanding data freshness
Keep the following data freshness characteristics in mind when interpreting query results:
Update schedule: Statistics are collected daily and updated by 05:00 the following day. Data for the current day is not available until then.
Pre-upgrade tables: Tables created before a V1.3 upgrade may have empty
create_timeand creation-related fields, because creation metadata was not collected before the upgrade. All tables created after the upgrade have complete metadata.Storage size vs.
pg_relation_size: The storage sizes inhg_table_infomay differ from values returned bypg_relation_size.hg_table_inforeports daily snapshots, whilepg_relation_sizereflects the current state and excludes binary logging storage.total_read_countandtotal_write_count: These fields are not exact values and are not reliable for analysis. Useread_sql_count_1dandwrite_sql_count_1dinstead, which provide daily counts for the previous day (00:00–24:00, UTC+8). These fields are available in V3.0 and later.
The hg_table_info table
After an instance is upgraded to V1.3, Hologres collects table information daily by default. The hg_table_info table contains the following fields.
| Field | Type | Description | Notes |
|---|---|---|---|
| db_name | text | The database where the table resides. | |
| schema_name | text | The schema where the table resides. | |
| table_name | text | The table name. | |
| table_id | text | The unique identifier of the table. | For foreign tables, the format is db.schema.table. |
| type | text | The table type. Valid values: TABLE (standard tables and child partitions), PARTITION TABLE (physical parent tables), LOGICAL PARTITION TABLE (logical partitioned tables; supported in V3.1.25/V3.2.8 and later—earlier versions report these as TABLE), FOREIGN TABLE, VIEW, MATERIALIZED VIEW. | For VIEW type: create_time and last_ddl_time are empty. For VIEW, FOREIGN TABLE, and PARTITION TABLE types: last_modify_time, last_access_time, hot_file_count, cold_file_count, total_read_count, and total_write_count are empty. |
| partition_spec | text | The partition condition. | Valid for child partitions only. |
| is_partition | boolean | Whether the table is a child partition. | |
| owner_name | text | The username of the table owner. | Join with the usename column of hg_query_log to look up owner details. |
| create_time | timestamp with time zone | The time the table was created. | |
| last_ddl_time | timestamp with time zone | The time the table schema was last modified. | |
| last_modify_time | timestamp with time zone | The time table data was last modified. | |
| last_access_time | timestamp with time zone | The time the table was last accessed. | |
| view_def | text | The view definition. | Valid for views only. |
| comment | text | The table or view description. | |
| hot_storage_size | bigint | Storage used by hot data, in bytes. | |
| cold_storage_size | bigint | Storage used by cold data, in bytes. | |
| hot_file_count | bigint | Number of hot data files. | |
| cold_file_count | bigint | Number of cold data files. | |
| table_meta | jsonb | Original metadata in JSONB format. | |
| row_count | bigint | Number of rows in the table or partition. | For parent tables, this is the total row count across all child tables. |
| collect_time | timestamp with time zone | The time the statistics snapshot was taken. | |
| partition_count | bigint | Number of child partitions. | Valid for parent tables only. |
| parent_schema_name | text | The schema of the parent table. | Valid for child partitions only. |
| parent_table_name | text | The name of the parent table. | Valid for child partitions only. |
| total_read_count | bigint | Cumulative read operations. Not an exact value, because SELECT, INSERT, UPDATE, and DELETE operations all increase the count. | Use read_sql_count_1d instead. |
| total_write_count | bigint | Cumulative write operations. Not an exact value, because INSERT, UPDATE, and DELETE operations all increase the count. | Use write_sql_count_1d instead. |
| read_sql_count_1d | bigint | Read operations on the previous day (00:00–24:00, UTC+8). | V3.0 and later. For partitioned tables, counts are recorded at the child partition level, not the parent table level. |
| write_sql_count_1d | bigint | Write operations on the previous day (00:00–24:00, UTC+8). | V3.0 and later. For partitioned tables, counts are recorded at the child partition level, not the parent table level. |
Grant query permissions
The required permissions depend on whether you need to query statistics across all databases or only the current database.
Query statistics for all databases
A superuser can view statistics for all databases in an instance. To grant superuser privileges:
-- Replace "Alibaba Cloud account ID" with the actual username.
-- For a RAM user, add the p4_ prefix to the account ID.
ALTER USER "Alibaba Cloud account ID" SUPERUSER;Non-superusers can also query all-database statistics by joining the pg_stat_scan_tables group (for versions earlier than V1.3.44) or the pg_read_all_stats group (for V1.3.44 and later). Contact a superuser to be added to the appropriate group.
-- For versions earlier than V1.3.44
GRANT pg_stat_scan_tables TO "Alibaba Cloud account ID"; -- Standard PostgreSQL authorization
CALL spm_grant('pg_stat_scan_tables', 'Alibaba Cloud account ID'); -- Simple Permission Model (SPM)
CALL slpm_grant('pg_stat_scan_tables', 'Alibaba Cloud account ID'); -- Schema-Level Permission Model (SLPM)
-- For V1.3.44 and later
GRANT pg_read_all_stats TO "Alibaba Cloud account ID"; -- Standard PostgreSQL authorization
CALL spm_grant('pg_read_all_stats', 'Alibaba Cloud account ID'); -- SPM
CALL slpm_grant('pg_read_all_stats', 'Alibaba Cloud account ID'); -- SLPMQuery statistics for the current database only
Enable the Simple Permission Model (SPM) or the Schema-Level Permission Model (SLPM) and add the user to the db_admin group. Users with the db_admin role can view statistics for all tables in the current database.
Without any of the above permissions, a user can only query statistics for tables they own in the current database.
CALL spm_grant('<db_name>_admin', 'Alibaba Cloud account ID'); -- SPM
CALL slpm_grant('<db_name>.admin', 'Alibaba Cloud account ID'); -- SLPMQuery table statistics
The following SQL examples query the hologres.hg_table_info table for different analysis goals. All examples filter on type = 'TABLE' to get complete statistics for non-partitioned internal tables.
Scenario 1: View access trends for all internal tables
This query returns weekly trends for all internal tables, including storage size, file count, daily read and write counts, and row count. Use it to identify changes in data volume and access patterns over time.
SELECT
db_name,
schema_name,
table_name,
collect_time::date AS collect_date,
hot_storage_size,
cold_storage_size,
hot_file_count,
cold_file_count,
read_sql_count_1d,
write_sql_count_1d,
row_count
FROM
hologres.hg_table_info
WHERE
collect_time > (current_date - interval '1 week')::timestamptz
AND type = 'TABLE'
ORDER BY collect_date DESC;Scenario 2: Find the top 10 tables by storage with access information
This query returns the 10 largest tables by total storage, along with their weekly read and write activity. Use it to identify high-storage tables that may be candidates for cleanup or optimization.
SELECT
db_name,
schema_name,
table_name,
hot_storage_size + cold_storage_size AS total_storage_size,
row_count,
sum(read_sql_count_1d) AS total_read_count,
sum(write_sql_count_1d) AS total_write_count
FROM
hologres.hg_table_info
WHERE
collect_time > (current_date - interval '1 week')::timestamptz
AND type = 'TABLE'
AND (
cold_storage_size IS NOT NULL
OR hot_storage_size IS NOT NULL
)
GROUP BY db_name, schema_name, table_name, total_storage_size, row_count
ORDER BY total_storage_size DESC
LIMIT 10;Scenario 3: Track weekly trends for the top 10 tables by storage
This query first identifies the top 10 tables by storage based on yesterday's snapshot, then retrieves their daily storage, row count, and access activity for the past week. Use it to monitor how your largest tables grow and are accessed over time.
WITH top10_table AS (
SELECT
db_name,
schema_name,
table_name,
hot_storage_size + cold_storage_size AS total_storage_size
FROM
hologres.hg_table_info
WHERE
collect_time >= (current_date - interval '1 day')::timestamptz -- Yesterday
AND collect_time < current_date
AND type = 'TABLE'
AND (cold_storage_size IS NOT NULL OR hot_storage_size IS NOT NULL)
ORDER BY total_storage_size DESC
LIMIT 10
)
SELECT
base.db_name,
base.schema_name,
base.table_name,
base.hot_storage_size + cold_storage_size AS total_storage_size,
base.row_count,
base.read_sql_count_1d,
base.write_sql_count_1d,
base.collect_time::date AS collect_date
FROM
hologres.hg_table_info AS base
LEFT JOIN
top10_table
ON
base.db_name = top10_table.db_name
AND base.schema_name = top10_table.schema_name
AND base.table_name = top10_table.table_name
WHERE
collect_time > (current_date - interval '1 week')::timestamptz
AND type = 'TABLE'
AND (cold_storage_size IS NOT NULL OR hot_storage_size IS NOT NULL)
ORDER BY total_storage_size DESC, collect_date DESC;Scenario 4: Track weekly trends for the 10 smallest tables by storage
This query identifies the 10 tables with the least storage based on yesterday's snapshot, then retrieves their weekly access and storage trends. Use it to find tables that may be unused or safe to archive.
WITH top10_table AS (
SELECT
db_name,
schema_name,
table_name,
hot_storage_size + cold_storage_size AS total_storage_size
FROM
hologres.hg_table_info
WHERE
collect_time >= (current_date - interval '1 day')::timestamptz -- Yesterday
AND collect_time < current_date
AND type = 'TABLE'
ORDER BY total_storage_size ASC
LIMIT 10
)
SELECT
base.db_name,
base.schema_name,
base.table_name,
base.hot_storage_size + cold_storage_size AS total_storage_size,
base.row_count,
base.read_sql_count_1d,
base.write_sql_count_1d,
base.collect_time::date AS collect_date
FROM
hologres.hg_table_info AS base
RIGHT JOIN
top10_table
ON
base.db_name = top10_table.db_name
AND base.schema_name = top10_table.schema_name
AND base.table_name = top10_table.table_name
WHERE
collect_time > (current_date - interval '1 week')::timestamptz
AND type = 'TABLE'
ORDER BY total_storage_size ASC, collect_date DESC;Scenario 5: Find tables with small file problems
This query returns each table's total storage, file count, and average file size, sorted by average file size in ascending order. Tables at the top of the results—with a low average file size—likely have a small file accumulation problem, which increases storage overhead and can degrade query performance. The query also joins with hg_table_group_properties to show the shard count for each table group, which helps assess whether the file count is proportionate to the table configuration.
Shard count is shown only for table groups in the current database. The shard_count column is empty for tables in other databases.SELECT
db_name,
schema_name,
table_name,
cold_storage_size + hot_storage_size AS total_storage_size,
cold_file_count + hot_file_count AS total_file_count,
(cold_storage_size + hot_storage_size) / (cold_file_count + hot_file_count) AS avg_file_size,
tmp_table_info.table_meta ->> 'table_group' AS table_group,
tg_info.shard_count
FROM
hologres.hg_table_info tmp_table_info
LEFT JOIN (
SELECT
tablegroup_name,
property_value AS shard_count
FROM
hologres.hg_table_group_properties
WHERE
property_key = 'shard_count'
) tg_info ON tmp_table_info.table_meta ->> 'table_group' = tg_info.tablegroup_name
WHERE
collect_time > (current_date - interval '1 day')::timestamptz
AND type = 'TABLE'
AND (
cold_storage_size IS NOT NULL
OR hot_storage_size IS NOT NULL
)
AND (
cold_file_count IS NOT NULL
OR hot_file_count IS NOT NULL
)
AND cold_file_count + hot_file_count <> 0
ORDER BY avg_file_size;Scenario 6: View row count changes on the last modification day
This query returns the last modification time of each table and the net change in row count compared to the day before the modification. Use this to audit data change events across your tables.
If your instance has many tables, add filters to the tmp_table_info CTE to avoid long query times. Examples are provided as inline comments.WITH tmp_table_info AS (
SELECT
db_name,
schema_name,
table_name,
row_count,
collect_time,
last_modify_time
FROM
hologres.hg_table_info
WHERE
last_modify_time IS NOT NULL
AND type = 'TABLE'
-- Add filters here if needed, for example:
-- AND collect_time > (current_date - interval '14 day')::timestamptz
-- AND table_name LIKE ''
)
SELECT
end_data.db_name,
end_data.schema_name,
end_data.table_name,
(end_data.row_count - start_data.row_count) AS modify_row_count,
end_data.row_count AS current_rows,
end_data.last_modify_time
FROM
(
SELECT
db_name,
schema_name,
table_name,
row_count,
last_modify_time
FROM
tmp_table_info
WHERE
collect_time > (current_date - interval '1 day')::timestamptz
) end_data
LEFT JOIN (
SELECT
db_name,
schema_name,
table_name,
row_count,
collect_time
FROM
tmp_table_info
) start_data ON (
end_data.db_name = start_data.db_name
AND end_data.schema_name = start_data.schema_name
AND end_data.table_name = start_data.table_name
AND end_data.last_modify_time::date = (start_data.collect_time + interval '1 day')::date
);