Hologres從 V1.3版本開始提供表統計信息日志系統表(hologres.hg_table_info)按日收集實例內表的統計信息,幫助您對實例中的表信息進行查看、分析,以便您可以根據這些信息采取優化措施。本文將會介紹在Hologres中如何查看表統計信息并分析。
使用限制
僅Hologres V1.3及以上版本支持查看表統計信息,如果您的實例是V1.3以下版本,請您使用自助升級或加入Hologres釘釘交流群反饋,詳情請參見如何獲取更多的在線支持?。
hologres.hg_table_info表的產出時效是T+1,當天的數據大概會在第二天凌晨5點前更新完成。Hologres實例從 V1.1版本升級到 V1.3版本的當天不會產出表統計信息,查詢時提示:
meta warehouse store currently not available
,需要在升級后的第二天查詢表統計信息。
注意事項
表統計信息日志默認保留30天的數據。
對于Hologres非分區內部表(type='TABLE'),可以查到詳細統計信息,如存儲空間、文件數、訪問累積次數和行記錄數。
對于其他對象(視圖,物化視圖,外表,分區父表),只能查到基本信息,如分區數量,外表對應外部表名,物化視圖與視圖定義等。
hologres.hg_table_info表屬于Hologres的元倉系統,hologres.hg_table_info查詢失敗不會影響實例中的業務Query運行,故hologres.hg_table_info表的穩定性不在產品的SLA保護范圍內。
hg_table_info表
hg_table_info
表主要包含的字段信息如下。
表統計信息日志存儲在hologres.hg_table_info系統表里,實例升級到 V1.3版本后,將會默認按天采集表信息。
部分字段存在值為空的情況,屬于歷史創建的表未能統計到創建信息導致,實例升級到V1.3版本后創建的表可以統計到信息。
字段 | 類型 | 描述 | 說明 |
db_name | text | 表所在數據庫名。 | 無 |
schema_name | text | 表所在Schema名。 | 無 |
table_name | text | 表名。 | 無 |
table_id | text | 表的唯一標識,外部表ID使用db.schema.table。 | 無 |
type | text | 表類型,包括:
|
|
partition_spec | text | 分區條件(分區子表有效)。 | 無 |
is_partition | boolean | 是否是分區子表。 | 無 |
owner_name | text | 表Owner的用戶名,可與hg_query_log的usename列做join。 | 無 |
create_time | timestamp with time zone | 表的創建時間。 | 無 |
last_ddl_time | timestamp with time zone | 最后一次更新表信息的時間。 | 無 |
last_modify_time | timestamp with time zone | 最后一次更新表信息的時間。 | 無 |
last_access_time | timestamp with time zone | 表最后的訪問時間。 | 無 |
view_def | text | 視圖的定義。 | 只對視圖有效。 |
comment | text | 表或視圖的描述信息。 | 無 |
hot_storage_size | bigint | 表占用的熱存空間,單位:Byte。 | hg_table_info查詢存儲量大小與使用pg_relation_size查詢存在差異屬于正常情況。原因是hg_table_info信息按天上報的,且pg_relation_size不包含binlog存儲大小。 |
code_storage_size | bigint | 表占用的冷存空間,單位:Byte。 | hg_table_info查詢存儲量大小與使用pg_relation_size查詢存在差異屬于正常情況。原因是hg_table_info信息按天上報的,且pg_relation_size不包含Binlog存儲大小。 |
hot_file_count | bigint | 表的熱存文件數。 | 無 |
cold_file_count | bigint | 表的冷存文件數。 | 無 |
table_meta | jsonb | 原始的Meta信息,格式為JSONB。 | 無 |
row_count | bigint | 表或者分區的行記錄數。 | 如果是分區父表,row_count為所有子表的總行數。 |
collect_time | timestamp with time zone | 數據上報的采集時間。 | 無 |
partition_count | bigint | 分區子表數量。 | 只有表為分區父表時有效。 |
parent_schema_name | text | 分區子表的父表Schema名。 | 只有表為分區子表時有效。 |
parent_table_name | text | 分區子表的父表表名。 | 只有表為分區子表時有效。 |
total_read_count | bigint | 累計讀表次數(非精確,SELECT,INSERT,UPDATE,DELETE 均會導致次數增加)。 | 非精確值,不建議使用。 |
total_write_count | bigint | 累計寫表次數(非精確,INSERT,UPDATE,DELETE 均會導致次數增加)。 | 非精確值,不建議使用。 |
read_sql_count_1d | bigint | T-1日(0-24點,+8時區)表的讀取總次數。 |
|
write_sql_count_1d | bigint | T-1日(0-24點,+8時區)表的寫入總次數。 |
|
授予查看權限
表統計信息日志需要有一定的權限才能查看,其權限規則和授權方式說明如下。
查看Hologres實例所有數據庫的表統計信息日志。
授予用戶Superuser權限。
Superuser賬號可以查看Hologres實例所有數據庫的表統計信息日志,給用戶授予Superuser用戶的權限,使用戶有權限查看實例所有數據庫的表統計信息日志。
--將“云賬號ID”替換為實際用戶名。如果是RAM用戶,賬號ID前需要添加“p4_”。 ALTER USER "云賬號ID" SUPERUSER;
將用戶添加到
pg_stat_scan_table
用戶組。除Superuser外,Hologres還支持通過設置用戶組
pg_stat_scan_tables
(V1.3.44以前版本)或pg_read_all_stats
(V1.3.44及以上版本)查看所有DB表統計信息日志,普通用戶如果需要查看所有日志,可以聯系Superuser授權加入該用戶組。授權命令如下。-- V1.3.44以前版本 GRANT pg_stat_scan_tables TO "云賬號ID";--專家權限模型授權 CALL spm_grant('pg_stat_scan_tables', '云賬號ID'); -- SPM權限模型 CALL slpm_grant('pg_stat_scan_tables', '云賬號ID'); -- SLPM權限模型 -- V1.3.44及以上版本 GRANT pg_read_all_stats TO "云賬號ID";--專家權限模型授權 CALL spm_grant('pg_read_all_stats', '云賬號ID'); -- SPM權限模型 CALL slpm_grant('pg_read_all_stats', '云賬號ID'); -- SLPM權限模型
查看本數據庫的表統計信息日志。
開啟簡單權限模型(SPM)或基于Schema級別的簡單權限模型(SLPM),將用戶加入
db_admin
用戶組,db_admin
角色可以查看本數據庫的表統計信息日志。說明普通用戶只能查詢當前賬號對應數據庫下自己為Owner的表統計信息日志。
CALL spm_grant('<db_name>_admin', '云賬號ID'); -- SPM權限模型 CALL slpm_grant('<db_name>.admin', '云賬號ID'); -- SLPM權限模型
查詢表統計信息趨勢的SQL命令
場景1:查看Holo內表的訪問趨勢
-- 實例所有內表的趨勢變化:占用存儲空間、文件數、讀取次數,寫入次數,行記錄數
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 ;
場景2:查看占用磁盤空間較大表的訪問情況
-- 查看占用磁盤空間最大的 (10) 個表的訪問情況
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;
場景3:查看存儲top10的表的訪問趨勢和數據量變化趨勢
-- 實例存儲top 10的表(已昨天統計值為準)近一周訪問趨勢和存儲量、數據量變化趨勢
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 -- 昨天
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;
場景4:查看存儲最少的表的訪問趨勢和數據量變化
-- 實例存儲最少的10個表(已昨天統計值為準)近一周訪問趨勢和存儲量、數據量變化趨勢
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 -- 昨天
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 ;
場景5:查詢小文件過多而導致占用磁盤空間大的表
-- 查看每個表的文件數和占用磁盤大小,并按平均文件大小排序
-- table group 只能顯示當前 db 的 shard count,其它 db 的顯示為空
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;
場景6:查看表最近一次修改表數據那天的行數變化
-- 查看表最近一次修改時間,相對前一次修改時間 的總共修改數據量
-- 當實例表數量很大時,建議對 CTE tmp_table_info 做過濾,以免因拉數據太大而導致查詢時間太久
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'
-- 在這里對 tmp_table_info 做一些過濾
-- 如 collect_time > (current_date - interval '14 day'):: timestamptz
-- 如 table_name like ''
-- 如 type = 'PARTITION'
)
SELECT
end_data.db_name AS db_name,
end_data.schema_name AS schema_name,
end_data.table_name AS 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 AS 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
);