All Products
Search
Document Center

Hologres:Get and analyze table statistics

Last Updated:Mar 25, 2026

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_info on 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_info is part of the Hologres metadata warehouse and is not covered by the product's Service-Level Agreement (SLA). Failures to query hg_table_info do 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_time and 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 in hg_table_info may differ from values returned by pg_relation_size. hg_table_info reports daily snapshots, while pg_relation_size reflects the current state and excludes binary logging storage.

  • total_read_count and total_write_count: These fields are not exact values and are not reliable for analysis. Use read_sql_count_1d and write_sql_count_1d instead, 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.

FieldTypeDescriptionNotes
db_nametextThe database where the table resides.
schema_nametextThe schema where the table resides.
table_nametextThe table name.
table_idtextThe unique identifier of the table.For foreign tables, the format is db.schema.table.
typetextThe 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_spectextThe partition condition.Valid for child partitions only.
is_partitionbooleanWhether the table is a child partition.
owner_nametextThe username of the table owner.Join with the usename column of hg_query_log to look up owner details.
create_timetimestamp with time zoneThe time the table was created.
last_ddl_timetimestamp with time zoneThe time the table schema was last modified.
last_modify_timetimestamp with time zoneThe time table data was last modified.
last_access_timetimestamp with time zoneThe time the table was last accessed.
view_deftextThe view definition.Valid for views only.
commenttextThe table or view description.
hot_storage_sizebigintStorage used by hot data, in bytes.
cold_storage_sizebigintStorage used by cold data, in bytes.
hot_file_countbigintNumber of hot data files.
cold_file_countbigintNumber of cold data files.
table_metajsonbOriginal metadata in JSONB format.
row_countbigintNumber of rows in the table or partition.For parent tables, this is the total row count across all child tables.
collect_timetimestamp with time zoneThe time the statistics snapshot was taken.
partition_countbigintNumber of child partitions.Valid for parent tables only.
parent_schema_nametextThe schema of the parent table.Valid for child partitions only.
parent_table_nametextThe name of the parent table.Valid for child partitions only.
total_read_countbigintCumulative 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_countbigintCumulative 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_1dbigintRead 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_1dbigintWrite 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');      -- SLPM

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

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