數(shù)據(jù)存儲冷熱分層
云原生數(shù)據(jù)倉庫AnalyticDB PostgreSQL版支持冷熱分層存儲,可以將訪問頻次低的熱表轉(zhuǎn)換為冷表存儲到OSS中,以降低存儲成本。本文介紹數(shù)據(jù)存儲冷熱分層的使用限制和使用方法。
本文中將存儲在本地磁盤的數(shù)據(jù)表稱為熱表,將存儲在遠端OSS的數(shù)據(jù)表稱為冷表。
版本約束
當實例為存儲彈性模式6.0版時,小版本需為v6.3.11.1及以上。
當實例為存儲彈性模式7.0版時,小版本需為v7.0.3.0及以上。
如何查看內(nèi)核版本,請參見查看內(nèi)核小版本。
Serverless版本不支持。
使用約束
AnalyticDB PostgreSQL 6.0版和AnalyticDB PostgreSQL 7.0版實例的數(shù)據(jù)存儲冷熱分層使用約束略有差異,請根據(jù)實例版本查看對應(yīng)的約束。
6.0版實例
支持將單個熱表轉(zhuǎn)為冷表。
支持將分區(qū)表的部分子分區(qū)轉(zhuǎn)為冷分區(qū),暫不支持將整個分區(qū)表父表轉(zhuǎn)為冷表。
熱表或者熱分區(qū)轉(zhuǎn)冷會建立臨時表存放臨時數(shù)據(jù),轉(zhuǎn)冷結(jié)束會自動清除。請確保各個segment節(jié)點上磁盤剩余空間大于當前正在轉(zhuǎn)冷的熱表空間之和。
熱表轉(zhuǎn)為冷表后,原表上關(guān)聯(lián)的主鍵、索引、序列、rule、注釋等會自動被刪除,且無法找回。
暫不支持將冷表或者冷分區(qū)直接轉(zhuǎn)熱,可以通過CREATE TABLE AS SELECT的方式將冷數(shù)據(jù)存儲至本地磁盤。
冷表或者冷分區(qū)的數(shù)據(jù)處于只讀狀態(tài),不支持修改(寫入、刪除、更新),或者任何DDL操作(ALTER COLUMN、DROP COLUMN等)。冷表支持刪除(DROP TABLE)。
冷表的底層存儲格式類似于AOCS表,自帶壓縮,所占空間會與原表大致相等。
冷表不支持索引。
7.0版實例
支持將單個熱表轉(zhuǎn)為冷表。
支持將分區(qū)表的部分子分區(qū)轉(zhuǎn)為冷分區(qū),暫不支持將整個分區(qū)表父表轉(zhuǎn)為冷表。
熱表轉(zhuǎn)為冷表后,原表上關(guān)聯(lián)的主鍵、索引、序列、rule、注釋等會自動被刪除,且無法找回。
暫不支持將冷表或者冷分區(qū)直接轉(zhuǎn)熱,可以通過CREATE TABLE AS SELECT的方式將冷數(shù)據(jù)存儲至本地磁盤。
冷表或者冷分區(qū)的數(shù)據(jù)允許讀取和追加寫入,不支持修改(刪除和更新),或者任何DDL操作(ALTER COLUMN、DROP COLUMN等)。冷表支持刪除(DROP TABLE)。
對于帶主鍵或者唯一索引的分區(qū)表,其子表暫不支持轉(zhuǎn)為冷表。帶有普通類型的索引的分區(qū)表則不受限制,其子表可以轉(zhuǎn)化為冷表。
冷表在OSS所占空間會與原表大致相等或略小。
冷表不支持索引。
冷存儲計費
熱表轉(zhuǎn)為冷表后數(shù)據(jù)存儲在遠端OSS,會產(chǎn)生存儲費用,計費規(guī)則如下:
冷存儲采取按量付費方式。
每5分鐘采集更新冷存使用量,小時級出賬。
價格和OSS的標準存儲價格一致,請參見OSS產(chǎn)品定價。
以中國內(nèi)地地域為例,OSS定價為0.12元/GB/月,每小時的定價則為0.000166666666667元/GB,實際價格以賬單頁面為準。
您可在
中查看冷存儲的計費賬單詳情。使用方法
遷移到冷表的過程中會有建立臨時表并寫入數(shù)據(jù),以及將數(shù)據(jù)上傳至OSS的過程,會存在一定的本地I/O和網(wǎng)絡(luò)I/O,可能對實例中已經(jīng)運行的查詢產(chǎn)生一定的性能影響,使用時請注意對業(yè)務(wù)的影響。
熱表轉(zhuǎn)為冷表后其占用的本地磁盤空間會被釋放。
AnalyticDB PostgreSQL 6.0版實例,系統(tǒng)會在設(shè)定的轉(zhuǎn)冷時間點開始調(diào)度,轉(zhuǎn)冷過程中調(diào)度和排隊會有一定耗時,AnalyticDB PostgreSQL 7.0版實例無需調(diào)度,在執(zhí)行轉(zhuǎn)冷語句后立即轉(zhuǎn)冷。具體需要的轉(zhuǎn)冷時間與實例規(guī)格、同時上傳的表數(shù)量和表的數(shù)據(jù)量有關(guān)。詳情請參見性能數(shù)據(jù)。
AnalyticDB PostgreSQL 6.0版和AnalyticDB PostgreSQL 7.0版實例的數(shù)據(jù)存儲冷熱分層使用方法不同,請根據(jù)實例版本選擇對應(yīng)的語法操作。
6.0版實例
普通表整表轉(zhuǎn)冷
語法
ALTER TABLE <tableName> SET ttl interval '<scheduling_interval>' move to storage_cold;
示例
創(chuàng)建一個普通表tiered_storage_heap
并插入數(shù)據(jù)。
CREATE TABLE tiered_storage_heap (a int, b int);
INSERT INTO tiered_storage_heap SELECT random() * 1000,1 FROM generate_series(1,1000);
示例一:指定三天后(3days)將普通表
tiered_storage_heap
轉(zhuǎn)冷。例如,2023年07月17日09:00:00執(zhí)行ALTER TABLE操作,那么三天后(2023年07月20日09:00:00)會將tiered_storage_heap
整表轉(zhuǎn)冷。ALTER TABLE tiered_storage_heap SET ttl interval '3days' move to storage_cold;
示例二:指定任意時間點(2023年07月28日 16:53:58)將普通表
tiered_storage_heap
轉(zhuǎn)冷。ALTER TABLE tiered_storage_heap SET ttl '2023-07-28 16:53:58'::Timestamp move to storage_cold;
示例三:將轉(zhuǎn)冷時間點設(shè)為過去的時間點,可以立刻對表進行轉(zhuǎn)冷。
指定轉(zhuǎn)冷時間點為三天前(-3days)。執(zhí)行如下命令,對表立刻轉(zhuǎn)冷。
ALTER TABLE tiered_storage_heap SET ttl interval '-3days' move to storage_cold;
指定過去的具體時間點。若當前時間為2023年07月17日16:53:58,您可以執(zhí)行如下命令,對表立刻轉(zhuǎn)冷。
ALTER TABLE tiered_storage_heap SET ttl '2022-07-16 16:53:58'::Timestamp move to storage_cold;
分區(qū)表按子分區(qū)轉(zhuǎn)冷
語法
ALTER TABLE <分區(qū)子表名> SET ttl interval '<scheduling_interval>' move to storage_cold;
您可以使用psql執(zhí)行\d+
查看具體分區(qū)表的子表名。
示例
創(chuàng)建一個分區(qū)表tiered_storage_partition_hdfs
。
CREATE TABLE tiered_storage_partition_hdfs(a int,b int) distributed by (a) partition by range(a) (start(1) end(20) every(10));
本示例會生成2個分區(qū)子表tiered_storage_partition_hdfs_1_prt_1
和tiered_storage_partition_hdfs_1_prt_2
。
向分區(qū)子表tiered_storage_partition_hdfs_1_prt_1
中插入數(shù)據(jù)。
INSERT INTO tiered_storage_partition_hdfs_1_prt_1 values(1, 1), (2, 2), (3, 3), (4, 4);
指定三天后將分區(qū)子表tiered_storage_partition_hdfs_1_prt_1
轉(zhuǎn)冷。例如,2023年07月17日09:00:00執(zhí)行ALTER TABLE操作,那么三天后(2023年07月20日09:00:00)會將tiered_storage_partition_hdfs_1_prt_1
子分區(qū)整表轉(zhuǎn)冷,其他分區(qū)均不會有任何遷移操作。
ALTER TABLE tiered_storage_partition_hdfs_1_prt_1 SET ttl interval '3days' move to storage_cold;
查詢指定表的冷熱狀態(tài)
您可以選擇任意一種方式查詢表的冷熱狀態(tài)。冷表返回cold,熱表返回hot。
方式一:
SELECT pg_tiered_storage_relation_status('<table_name>'::regclass::oid::bigint);
方式二:
SELECT pg_tiered_storage_relation_status(<表的oid>::bigint);
通過
SELECT oid FROM pg_class where relname='<table_name>';
查詢表的oid。
7.0版實例
普通表整表轉(zhuǎn)冷
語法
SELECT pg_tiered_storage_move_table_to_storage_cold('<schema_name>', '<table_name>');
示例
在public
的Schema中創(chuàng)建一個普通表tiered_storage_heap_oss
并插入數(shù)據(jù)。
CREATE TABLE tiered_storage_heap_oss (a int, b int) DISTRIBUTED BY(a) ;
INSERT INTO tiered_storage_heap_oss SELECT random() * 1000,1 FROM generate_series(1,100);
示例一:整表立即轉(zhuǎn)冷。
執(zhí)行以下語句,將普通表整表立即轉(zhuǎn)冷。
SELECT pg_tiered_storage_move_table_to_storage_cold('public', 'tiered_storage_heap_oss');
示例二:使用pg_cron設(shè)置整表定時轉(zhuǎn)冷。
假設(shè)執(zhí)行用戶為
etl_user
,將數(shù)據(jù)庫etl
中的普通表tiered_storage_heap_oss
,設(shè)置在次日凌晨1點將普通表轉(zhuǎn)冷。連接到postgres
數(shù)據(jù)庫,執(zhí)行以下語句。SELECT cron.schedule('etl_table_transfer_to_cold', '0 1 * * *', 'SELECT pg_tiered_storage_move_table_to_storage_cold('public', 'tiered_storage_heap_oss');', 'etl', 'etl_user');
次日凌晨1點后檢查轉(zhuǎn)冷成功后,可執(zhí)行以下語句,刪除該定時任務(wù)。
SELECT cron.unschedule(<定時任務(wù)ID>);
說明定時任務(wù)ID為創(chuàng)建任務(wù)時自動生成的,可以通過查看
cron.job
表的jobid
字段查看。
分區(qū)表按子分區(qū)轉(zhuǎn)冷
語法
SELECT pg_tiered_storage_move_table_to_storage_cold('<schema_name>', '<分區(qū)子表名>');
您可以使用psql執(zhí)行\d+
查看具體分區(qū)表的子表名。
示例
示例一:對分區(qū)子表立即轉(zhuǎn)冷。
在
public
的Schema中創(chuàng)建一個分區(qū)表tiered_storage_partition_oss
。CREATE TABLE tiered_storage_partition_oss(a int,b int) DISTRIBUTED BY (a) PARTITION BY range(a) (start(1) end(20) every(10));
說明本示例會生成2個分區(qū)子表
tiered_storage_partition_oss_1_prt_1
和tiered_storage_partition_oss_1_prt_2
。向分區(qū)子表
tiered_storage_partition_oss_1_prt_1
中插入數(shù)據(jù)。INSERT INTO tiered_storage_partition_oss_1_prt_1 VALUES(1, 1), (2, 2), (3, 3), (4, 4);
將分區(qū)子表立即轉(zhuǎn)冷。
SELECT pg_tiered_storage_move_table_to_storage_cold('public', 'tiered_storage_partition_oss_1_prt_1');
示例二:使用pg_cron設(shè)置按天分區(qū)的分區(qū)子表定時轉(zhuǎn)冷。
在數(shù)據(jù)庫
etl
中創(chuàng)建按天分區(qū)的daily_log_details
分區(qū)表。CREATE TABLE daily_log_details (id INT, log_message text, created_date character varying(64)) PARTITION BY LIST (created_date) ( PARTITION p20230601 VALUES ('20230601'), PARTITION p20230602 VALUES ('20230602'), PARTITION p20230603 VALUES ('20230603'), PARTITION p20230604 VALUES ('20230604'), PARTITION p20230605 VALUES ('20230605'), PARTITION p20230606 VALUES ('20230606'), PARTITION p20230607 VALUES ('20230607'), PARTITION p20230608 VALUES ('20230608'), PARTITION p20230609 VALUES ('20230609'), PARTITION p20230610 VALUES ('20230610'), PARTITION p20230611 VALUES ('20230611'), DEFAULT PARTITION others );
設(shè)置將10天前的分區(qū)子表轉(zhuǎn)冷,執(zhí)行用戶為
etl_user
,轉(zhuǎn)冷執(zhí)行時間為3點。按照如下步驟操作。在數(shù)據(jù)庫
etl
中創(chuàng)建清理函數(shù)。CREATE OR REPLACE FUNCTION pg_tiered_storage_move_partition_daily_table_to_cold_storage(schemaname text, tablename text) RETURNS void AS $$ DECLARE fetch_overdue_partition_sql text; cold_storage_sql text; target record; BEGIN fetch_overdue_partition_sql := 'WITH targetpartitions AS (SELECT * FROM pg_partitions WHERE tablename = $1 AND schemaname = $2 AND partitionlevel = 1 AND partitionisdefault = FALSE) SELECT partitiontablename FROM targetpartitions WHERE to_date(substring(targetpartitions.partitionname FROM 2), ''YYYYMMDD'') <= current_date - INTERVAL ''10 days'''; -- fetch overdue partitions FOR target IN EXECUTE fetch_overdue_partition_sql USING tablename, schemaname LOOP cold_storage_sql := 'SELECT pg_tiered_storage_move_table_to_storage_cold($1::text, $2::text)'; raise notice 'sql %', cold_storage_sql; EXECUTE cold_storage_sql USING schemaname, target.partitiontablename; END LOOP; END; $$ LANGUAGE plpgsql;
連接到
postgres
數(shù)據(jù)庫執(zhí)行轉(zhuǎn)冷語句。SELECT cron.schedule('etl_daily_transfer_to_cold', '0 3 * * *', 'SELECT pg_tiered_storage_move_partition_daily_table_to_cold_storage(''public'', ''daily_log_details'');', 'etl', 'etl_user');
示例三:使用pg_cron設(shè)置按月分區(qū)的分區(qū)子表定時轉(zhuǎn)冷。
在數(shù)據(jù)庫
etl
中創(chuàng)建按月分區(qū)的month_log_details
分區(qū)表。CREATE TABLE month_log_details (id INT, log_message text, created_date character varying(64)) PARTITION BY LIST (created_date) ( PARTITION p202306 VALUES ('202306'), PARTITION p202307 VALUES ('202307'), PARTITION p202308 VALUES ('202308'), PARTITION p202309 VALUES ('202309'), PARTITION p202310 VALUES ('202310'), DEFAULT PARTITION others );
設(shè)置將3個月前的分區(qū)子表轉(zhuǎn)冷,執(zhí)行用戶為
etl_user
,轉(zhuǎn)冷執(zhí)行時間為5點。按照如下步驟操作。在數(shù)據(jù)庫
etl
中創(chuàng)建清理函數(shù)。CREATE OR REPLACE FUNCTION pg_tiered_storage_move_partition_table_to_cold_storage(schemaname text, tablename text) RETURNS void AS $$ DECLARE fetch_overdue_partition_sql text; cold_storage_sql text; target record; BEGIN fetch_overdue_partition_sql := 'WITH targetpartitions AS (SELECT * FROM pg_partitions WHERE tablename = $1 AND schemaname = $2 AND partitionlevel = 1 AND partitionisdefault = FALSE) SELECT partitiontablename FROM targetpartitions WHERE to_date(substring(targetpartitions.partitionname FROM 2), ''YYYYMM'') <= current_date - INTERVAL ''3 months'''; -- fetch overdue partitions FOR target IN EXECUTE fetch_overdue_partition_sql USING tablename, schemaname LOOP cold_storage_sql := 'SELECT pg_tiered_storage_move_table_to_storage_cold($1::text, $2::text)'; raise notice 'sql %', cold_storage_sql; EXECUTE cold_storage_sql USING schemaname, target.partitiontablename; END LOOP; END; $$ LANGUAGE plpgsql;
連接到
postgres
數(shù)據(jù)庫執(zhí)行轉(zhuǎn)冷語句。SELECT cron.schedule('etl_month_transfer_to_cold', '0 5 1 * *', 'SELECT pg_tiered_storage_move_partition_table_to_cold_storage(''public'', ''month_log_details'');', 'etl', 'etl_user');
查詢指定表的冷熱狀態(tài)
執(zhí)行以下語句,查詢表的冷熱狀態(tài)。冷表返回cold,熱表返回hot。
SELECT pg_tiered_storage_table_status('<schema_name>', '<table_name>|<分區(qū)子表名>')
查看冷熱數(shù)據(jù)存儲量
登錄云原生數(shù)據(jù)倉庫AnalyticDB PostgreSQL版控制臺,在基本信息頁面的實例運行狀態(tài)卡片中查看熱存儲總量和冷存儲總量。
備份恢復(fù)
AnalyticDB PostgreSQL版冷熱分層存儲支持備份恢復(fù),具體恢復(fù)規(guī)則如下。
6.0版實例
當具備完整備份時,可以恢復(fù)到任意時間點的狀態(tài),恢復(fù)時間點的冷熱狀態(tài)與備份時刻一致。
7.0版實例
當具備完整備份時,可以恢復(fù)到指定時間點的狀態(tài)?;謴?fù)時間點的冷熱狀態(tài)與備份時刻一致。AnalyticDB PostgreSQL 7.0版存在如下限制:
如果數(shù)據(jù)表轉(zhuǎn)冷后無數(shù)據(jù)寫入,可以恢復(fù)到任意時間點的狀態(tài)。
如果數(shù)據(jù)表轉(zhuǎn)冷后有數(shù)據(jù)寫入,可以恢復(fù)到轉(zhuǎn)冷前任何備份點的狀態(tài),如果恢復(fù)到冷存狀態(tài),暫時只能恢復(fù)到冷表最后一次寫入對應(yīng)的狀態(tài)。
為了支持備份恢復(fù),被DROP后的數(shù)據(jù)表對應(yīng)的OSS空間不會立刻釋放,會額外延長保存一段時間。延長保存的時間與備份恢復(fù)設(shè)置的數(shù)據(jù)備份保留天數(shù)一致。延長保存的時間內(nèi)對應(yīng)OSS空間依然會產(chǎn)生費用。
備份恢復(fù)的詳細信息,請參見備份恢復(fù)功能介紹。
擴縮容
AnalyticDB PostgreSQL 6.0版實例縮容會時會將冷表遷移至本地臨時表以進行數(shù)據(jù)重分布,縮容完成后會重新上傳數(shù)據(jù)至OSS并清理本地臨時表,需要保證縮容后的所有節(jié)點剩余空間大于冷表占用空間之和才能縮容成功??s容過程會從OSS下載數(shù)據(jù),縮容完成時間受限于OSS下載數(shù)據(jù)的帶寬,請合理評估縮容時間。
對于AnalyticDB PostgreSQL 7.0版實例,擴縮容不涉及冷存部分的數(shù)據(jù),不需要進行重分布或者數(shù)據(jù)拉回本地,不需要考慮冷存所占磁盤空間。
性能數(shù)據(jù)
按照如下語句分別對節(jié)點規(guī)格為2C8G的4節(jié)點實例和2C8G的8節(jié)點實例進行測試。
CREATE TABLE t333 (a int, b int);
INSERT INTO t333 SELECT random() * 1000000, random()*1000000 FROM generate_series(1,3000000000);
AnalyticDB PostgreSQL 6.0版實例執(zhí)行ALTER TABLE t333 SET ttl interval '-3days' move to storage_cold;
轉(zhuǎn)冷語句。
AnalyticDB PostgreSQL 7.0版實例執(zhí)行SELECT pg_tiered_storage_move_table_to_storage_cold('public', 't333');
轉(zhuǎn)冷語句。
單表轉(zhuǎn)冷時間的測試結(jié)果如下。
熱表大小(GB) | 4節(jié)點實例轉(zhuǎn)冷時間(秒) | 8節(jié)點實例轉(zhuǎn)冷時間(秒) | ||
6.0版實例 | 7.0版實例 | 6.0版實例 | 7.0版實例 | |
1 | 10 | 5 | 5 | 2.8 |
10 | 96 | 48 | 42 | 25.2 |
100 | 848 | 490 | 333 | 243 |