Hologres从V1.3.37版本开始支持冷热数据分层存储,帮助客户科学管理数据分层。本文为您详细介绍数据分层存储的使用方式。
功能介绍
Hologres的数据存储类型分为标准存储、低频访问存储。
- 标准存储即全SSD热存储,是Hologres的默认存储,满足低延时、高性能访问数据需求,对于大多数使用场景而言,标准存储是最有效且最具成本效益的选择,文中简称为热存。 
- 低频访问存储即全HDD冷存,满足低频访问数据的低成本存储需求,适用于对延迟不敏感或不常访问的超大型数据集,文中简称为冷存。 
- 对于主从实例,建议升级到V1.3.55及以上版本开启冷存。 
同时也支持表级别的冷热数据分层,可以使用Hologres提供的CREATE PARTITION TABLE功能动态的设置分区子表的存储介质。
Hologres从 V2.1版本开始支持基于SSD的缓存加速,帮助您提高冷存访问速度,当前仅支持默认分配的缓存空间。缓存加速默认开启,预计访问性能会提高一倍以上。
前提条件
- 仅HologresV1.3.37及以上版本支持数据冷热分层存储,如果您的实例低于该版本,请您使用自助升级或加入Hologres钉钉交流群反馈,详情请参见如何获取更多的在线支持?。 
- 对于低版本的包年包月的实例,升级到V1.3.37版本后,实例的低频访问存储的配额默认是0GB。 
注意事项
- Hologres表的存储分为Data和Meta两部分,Data为用户的数据,Meta为表的一些元数据信息。在冷热分层存储中,用户只能设置表的Data部分存储的存储介质。出于性能考虑Meta只能存储在热存储,因此即使将表的存储策略设置为冷存储,也会占用少量热存储介质,因此会产生少量的热存储费用。 
- 为了不影响用户服务,冷热搬迁的任务优先级较低,即用户修改表Data的存储策略后,不是立即生效,Hologres会在后台异步进行数据冷热搬迁,搬迁时间默认为当天晚上0点,从V2.2版本开始支持自定义搬迁时间,详情请参见动态分区管理。 
- 向冷存表新写数据时,数据会先写到热存储,后台任务会异步的搬迁至冷存储,因此会产生一定的热存储费用。 
- 由于磁盘寻道时间的限制,不推荐使用冷存表支撑点查场景(例如Flink维度表,Serving场景等)。冷存表支持的每秒读取行数比热存表低2个数量级。 
- 不推荐将行存表的存储策略设为冷存储介质。 
- 批量进行冷热数据转换过程中会打开所有表的 - tablet,导致内存占用增加,建议一次性转换的表数量不超过200张。
创建冷热分层表
在执行建表时,您可以通过设置SET_TABLE_PROPERTY中的storage_mode参数来指定表的数据存储策略。详情请参见CREATE TABLE。
非分区表
指定非分区表的存储策略
如果是非分区表,可以通过SET_TABLE_PROPERTY来设置表的存储策略。支持的选项有:
- hot(热存储)。 
- cold(冷存储)。 
例如将tbl1设置为使用冷存存储,代码如下:
-- 建表时指定存储策略为冷存储
BEGIN;
CREATE TABLE tbl1 (
 "id" int NOT NULL,
 "name" text NOT NULL
);
CALL set_table_property('tbl1', 'storage_mode', 'cold');
COMMIT;修改非分区表的存储介质
Hologres支持建表后修改存储介质。例如将表tbl1的存储介质改为热存存储,系统会异步的将数据搬迁到热存存储。示例如下:
-- 建表后修改存储介质为热存储
CALL set_table_property('tbl1', 'storage_mode', 'hot');分区表
创建分区表的存储策略
分区表也可以通过SET_TABLE_PROPERTY来设置表的存储策略,分区子表默认继承父表的存储属性,也可以分别设置父表和子表的存储策略。支持的选项有:
- hot(热存储)。 
- cold(冷存储)。 
例如将分区父表(tbl2)设置为使用冷存存储,之后该分区父表(tbl2)对应的分区子表(tbl2_v1)都会使用冷存进行数据存储,代码如下:
-- 建表时指定存储策略为冷存储
BEGIN;
CREATE TABLE tbl2(
  c1 text NOT NULL,
  c2 text
)
PARTITION BY LIST(c2);
CALL set_table_property('tbl2', 'storage_mode', 'cold');
CREATE TABLE tbl2_v1 PARTITION OF tbl2 FOR VALUES IN ('v1');
COMMIT;修改分区表的存储
Hologres支持在建表后修改存储介质。例如将分区父表tbl2的存储介质改为热存存储,系统会将该分区父表对应所有分区子表的数据都异步的搬迁到热存存储。示例如下:
-- 建表后修改存储策略为热存储介质
CALL set_table_property('tbl2', 'storage_mode', 'hot');如果您需要单独设置某个分区子表使用冷存存储,则需要修改该分区子表的storage_mode属性。示例如下:
-- 创建多个分区子表
CREATE TABLE tbl2_v2 PARTITION OF tbl2 FOR VALUES IN ('v2');
CREATE TABLE tbl2_v3 PARTITION OF tbl2 FOR VALUES IN ('v3');
-- 查询表属性,当前默认继承父表的热存属性
SELECT * FROM hg_table_storage_status('public', 'tbl2');
-- 修改分区子表为冷存存储
CALL set_table_property('tbl2_v3', 'storage_mode', 'cold');
                动态管理分区表的存储介质
为了更智能的管理表分区的存储介质,可以使用动态分区功能来设置数据冷热转换规则,实现智能冷热分层存储,有效的平衡成本和性能。更多对于动态管理分区表的信息,详情请参见动态分区管理。
查询存储介质状态
可以通过调用hg_table_storage_status函数,查询表的存储状态。hg_table_storage_status仅显示数据存储大小,不包含Meta存储大小。使用方法如下:
SELECT * FROM hg_table_storage_status('<schema_name>', '<table_name>');| 参数 | 描述 | 
| 
 | 表的Schema名 | 
| 
 | 表名 | 
返回结果如下:
| 列名 | 内容 | 
| table_name | 
 | 
| hot_size | 热存储的大小,单位Byte | 
| cold_size | 冷存储的大小,单位Byte | 
| status | 状态: 
 | 
示例如下:
-- 非分区父表
SELECT * FROM hg_table_storage_status('public', 'tbl1');--返回单位是Byte
 table_name | hot_size |   cold_size   | status
------------+----------+---------------+--------
 tbl1       |  145643  |      3685     | transferring
-- 分区父表
SELECT * FROM hg_table_storage_status('public', 'tbl2');--返回单位是Byte
   table_name    | hot_size | cold_size | status
-----------------+----------+-----------+--------
 tbl2_2022062222 |        0 |         0 | hot
 tbl2_2022062221 |     1125 |         0 | hot
 tbl2_2022062220 |     1245 |         0 | hot
 tbl2_2022062219 |     1358 |         0 | hot
 tbl2_2022062218 |        0 |      1875 | cold
 tbl2_2022062217 |        0 |      1143 | cold
 tbl2_2022062216 |        0 |      1299 | cold查询表访问频率
Hologres从V1.3.37版本开始提供日志系统表hologres.hg_table_info来按日收集实例内表的统计信息,帮助您对实例中的表信息进行查看、分析,以针对性的做优化,详情请参见表统计信息查看与分析,我们可以通过查询该表获取冷热数据的存储量、表数据的访问频次、分区数据访问频次,以此来判断是否需要做冷热数据转换,详细查询语句如下:
非分区表
SELECT a.table_name,
       (a.total_read_count - b.total_read_count) AS read_count,
       (a.total_write_count - b.total_write_count) AS write_count,
       a.hot_storage_size
FROM (SELECT * FROM hologres.hg_table_info
      WHERE type='TABLE' AND collect_time::DATE = CURRENT_DATE - interval '1 day') a
JOIN
    (SELECT * FROM hologres.hg_table_info
    WHERE type='TABLE' AND collect_time::DATE = CURRENT_DATE - interval '${days} day') b
ON a.table_name = b.table_name
ORDER BY hot_storage_size DESC;分区表
查询所有分区:
SELECT parent_table_name,count(*) AS partition_cnt, 
       sum(hot_storage_size)/1024/1024/1024 AS hot_size_gb 
FROM hologres.hg_table_info
WHERE type = 'PARTITION' AND collect_time::DATE = CURRENT_DATE - interval '1 day'
GROUP BY parent_table_name
ORDER BY hot_size_gb DESC;查询特定分区访问频次:
SELECT a.table_name,
      (a.total_read_count - b.total_read_count) as read_count,
      (a.total_write_count - b.total_write_count) as write_count,
       a.hot_storage_size
FROM (SELECT * FROM hologres.hg_table_info
      WHERE type = 'PARTITION'
      AND parent_table_name = '${p_table_name}'
      AND collect_time::DATE = CURRENT_DATE - interval '1 day') a
JOIN
     (SELECT * FROM hologres.hg_table_info
     WHERE type = 'PARTITION'
     AND parent_table_name = '${p_table_name}'
     AND collect_time::DATE = CURRENT_DATE - interval '${days} day') b
ON a.table_name = b.table_name
ORDER BY table_name DESC;