Hologres支持三種表存儲格式,分別為:行存、列存和行列共存,不同的存儲格式適用于不同的查詢場景,您需要根據表的使用場景設置表的存儲格式,合適的存儲格式可以顯著提高數據處理和查詢速度,同時也可以節省存儲空間。
設置存儲格式語法
在Hologres中支持行存、列存和行列共存三種存儲格式,在建表時通過設置orientation
屬性指定表的存儲格式,語法如下:
-- 2.1版本起支持
CREATE TABLE <table_name> (...) WITH (orientation = '[column | row | row,column]');
-- 所有版本支持
BEGIN;
CREATE TABLE <table_name> (...);
call set_table_property('<table_name>', 'orientation', '[column | row | row,column]');
COMMIT;
table_name:表名稱。
orientation:指定了數據庫表在Hologres中的存儲模式是列存還是行存,Hologres從 V1.1版本開始支持行列共存的模式。
建表時默認為列存(column storage)形式。行存或行列共存需要在建表時顯式指定。修改表的存儲格式需要重新建表,不能直接轉換。
使用建議
表的存儲格式使用建議如下。
存儲格式 | 適用場景 | 列限制 | 使用說明 |
列存 | 適用于OLAP場景,適合各種復雜查詢、數據關聯、掃描、過濾和統計。 | 建議不超過300列。 | 列存會默認創建更多的索引,包括對字符串類型創建bitmap索引,這些索引可以顯著加速查詢過濾和統計。 |
行存 | 適合基于Primary Key點查的場景,即查詢語句如下所示。
| 建議不超過3000列。 | 行存默認僅對主鍵創建索引,僅支持主鍵的快速查詢,使用場景也受到限制。 |
行列共存 | 支持行存和列存的所有場景,以及非主鍵點查的場景。 | 建議不超過300列。 | 行列共存適用的場景更廣,但會帶來更多的存儲開銷,以及內部數據狀態同步的開銷。 |
技術原理
列存
如果表是列存,那么數據將會按照列的形式存儲。列存默認使用ORC格式,采用各種類型的Encoding算法(如RLE、字典編碼等)對數據進行編碼,并且對編碼后的數據應用主流壓縮算法(如Snappy、 Zlib、 Zstd、 Lz4等)對數據進一步進行壓縮,并結合Bitmap index、延遲物化等機制,提升數據的存儲和查詢效率。
系統會為每張表在底層存儲一個主鍵索引文件,詳情請參見主鍵Primary Key。列存表如果設置了主鍵PK,系統會自動生成一個Row Identifier(RID),用于快速定位整行數據,同時如果為查詢的列設置合適的索引(如Distribution Key、Clustering Key等),那么就可以通過索引快速定位到數據所在的分片和文件,從而提升查詢性能,因此列存的適用范圍更廣,通常用于OLAP查詢的場景。示例如下。
V2.1版本起支持的建表語法:
CREATE TABLE public.tbl_col ( id text NOT NULL, name text NOT NULL, class text NOT NULL, in_time timestamptz NOT NULL, PRIMARY KEY (id) ) WITH ( orientation = 'column', clustering_key = 'class', bitmap_columns = 'name', event_time_column = 'in_time' ); select * from public.tbl_col where id ='3333'; select id, class,name from public.tbl_col where id < '3333' order by id;
所有版本支持的建表語法:
begin; create table public.tbl_col ( id text NOT NULL, name text NOT NULL, class text NOT NULL, in_time TIMESTAMPTZ NOT NULL, PRIMARY KEY (id) ); call set_table_property('public.tbl_col', 'orientation', 'column'); call set_table_property('public.tbl_col', 'clustering_key', 'class'); call set_table_property('public.tbl_col', 'bitmap_columns', 'name'); call set_table_property('public.tbl_col', 'event_time_column', 'in_time'); commit; select * from public.tbl_col where id ='3333'; select id, class,name from public.tbl_col where id < '3333' order by id;
示意圖如下。
行存
如果Hologres的表設置的是行存,那么數據將會按照行存儲。行存默認使用SST格式,數據按照Key有序分塊壓縮存儲,并且通過Block Index、Bloom Filter等索引,以及后臺Compaction機制對文件進行整理,優化點查查詢效率。
(推薦)設置主鍵Primary Key
系統會為每張表在底層存儲一個主鍵索引文件,詳情請參見主鍵Primary Key。行存表設置了Primary Key(PK)的場景,系統會自動生成一個Row Identifier(RID),RID用于定位整行數據,同時系統也會將PK設置為Distribution Key和Clustering Key,這樣就能快速定位到數據所在的Shard和文件,在基于主鍵查詢的場景上,只需要掃描一個主鍵就能快速拿到所有列的全行數據,提升查詢效率,SQL示例如下。
V2.1版本起支持的建表語法:
CREATE TABLE public.tbl_row ( id text NOT NULL, name text NOT NULL, class text, PRIMARY KEY (id) ) WITH ( orientation = 'row', clustering_key = 'id', distribution_key = 'id' ); --基于PK的點查示例 select * from public.tbl_row where id ='1111'; --查詢多個key select * from public.tbl_row where id in ('1111','2222','3333');
所有版本支持的建表語法:
begin; create table public.tbl_row ( id text NOT NULL, name text NOT NULL, class text , PRIMARY KEY (id) ); call set_table_property('public.tbl_row', 'orientation', 'row'); call set_table_property('public.tbl_row', 'clustering_key', 'id'); call set_table_property('public.tbl_row', 'distribution_key', 'id'); commit; --基于PK的點查示例 select * from public.tbl_row where id ='1111'; --查詢多個key select * from public.tbl_row where id in ('1111','2222','3333');
示意圖如下。
(不建議使用)設置的PK和Clustering Key不一致
但如果在建表時,設置表為行存表,且將PK和Clustering Key設置為不同的字段,查詢時,系統會根據PK定位到Clustering Key和RID,再通過Clustering Key和RID快速定位到全行數據,相當于掃描了兩次,有一定的性能犧牲,SQL示例如下。
V2.1版本起支持的建表語法,設置行存表,PK和Clustering Key不一致:
CREATE TABLE public.tbl_row ( id text NOT NULL, name text NOT NULL, class text, PRIMARY KEY (id) ) WITH ( orientation = 'row', clustering_key = 'name', distribution_key = 'id' );
所有版本支持的建表語法,設置行存表,PK和Clustering Key不一致:
begin; create table public.tbl_row ( id text NOT NULL, name text NOT NULL, class text , PRIMARY KEY (id) ); call set_table_property('public.tbl_row', 'orientation', 'row'); call set_table_property('public.tbl_row', 'clustering_key', 'name'); call set_table_property('public.tbl_row', 'distribution_key', 'id'); commit;
示意圖如下所示。
綜上:行存表非常適用于基于PK的點查場景,能夠實現高QPS的點查。同時建表時建議只設置PK,系統會自動將PK設置為Distribution Key和Clustering Key,以提升查詢性能。不建議將PK和Clustering Key設置為不同的字段,設置為不同的字段會有一定的性能犧牲。
行列共存
在實際應用場景中,一張表可能用于主鍵點查,又用于OLAP查詢,因此Hologres在V1.1版本支持了行列共存的存儲格式。行列共存同時擁有行列和列存的能力,既支持高性能的基于PK點查,又支持OLAP分析。數據在底層存儲時會存儲兩份,一份按照行存格式存儲,一份按照列存格式存儲,因此會帶來更多的存儲開銷。
數據寫入時,會同時寫一份行存格式和寫一份列存格式,只有兩份數據都寫完了才會返回成功,保證數據的原子性。
數據查詢時,優化器會根據SQL,解析出對應的執行計劃,執行引擎會根據執行計劃判斷走行存還是列存的查詢效率更高,要求行列共存的表必須設置主鍵:
對于主鍵點查場景(如
select * from tbl where pk=xxx
語句)以及Fixed Plan加速SQL執行場景,優化器會默認走行存主鍵點查的路徑。對于非主鍵點查場景(如
select * from tbl where col1=xx and col2=yyy
語句),尤其是表的列很多,且查詢結果需要展示很多列,行列共存針對該場景,優化器在生成執行計劃時,會先讀取列存表的數據,讀取完成后根據列存鍵值Key查詢行存表的數據,避免全表掃描,提升非主鍵查詢性能。該場景能充分發揮行列共存的優勢,提高數據的快速檢索性能。對于其他的普通查詢,則會默認走列存。
因此行列共存表在通常查詢場景,尤其是非主鍵點查場景,查詢效率更好,示例如下。
V2.1版本起支持的建表語法:
CREATE TABLE public.tbl_row_col ( id text NOT NULL, name text NOT NULL, class text NOT NULL, PRIMARY KEY (id) ) WITH ( orientation = 'row,column', distribution_key = 'id', clustering_key = 'class', bitmap_columns = 'name' ); SELECT * FROM public.tbl_row_col where id =‘2222’; --基于主鍵的點查 SELECT * FROM public.tbl_row_col where class=‘二班’;--非主鍵點查 SELECT * FROM public.tbl_row_col where id =‘2222’ and class=‘二班’; --普通OLAP查
所有版本支持的建表語法:
begin; create table public.tbl_row_col ( id text NOT NULL, name text NOT NULL, class text , PRIMARY KEY (id) ); call set_table_property('public.tbl_row_col', 'orientation','row,column'); call set_table_property('public.tbl_row_col', 'distribution_key','id'); call set_table_property('public.tbl_row_col', 'clustering_key','name'); call set_table_property('public.tbl_row_col', 'bitmap_columns','class'); commit; SELECT * FROM public.tbl_row_col where id =‘2222’; --基于主鍵的點查 SELECT * FROM public.tbl_row_col where class=‘二班’;--非主鍵點查 SELECT * FROM public.tbl_row_col where id =‘2222’ and class=‘二班’; --普通OLAP查
示意圖如下。
使用示例
創建不同存儲模式的表使用示例如下。
V2.1版本起支持的建表語法:
--建行存表 CREATE TABLE public.tbl_row ( a integer NOT NULL, b text NOT NULL, PRIMARY KEY (a) ) WITH ( orientation = 'row' ); --建列存表 CREATE TABLE tbl_col ( a int NOT NULL, b text NOT NULL ) WITH ( orientation = 'column' ); --建行列共存 CREATE TABLE tbl_col_row ( pk text NOT NULL, col1 text, col2 text, col3 text, PRIMARY KEY (pk) ) WITH ( orientation = 'row,column' );
所有版本支持的建表語法:
--建行存表 begin; create table public.tbl_row ( a integer NOT NULL, b text NOT NULL ,PRIMARY KEY (a) ); call set_table_property('public.tbl_row', 'orientation', 'row'); commit; --建列存表 begin; create table tbl_col ( a int not null, b text not null); call set_table_property('tbl_col', 'orientation', 'column'); commit; --建行列共存 begin; create table tbl_col_row ( pk text not null, col1 text, col2 text, col3 text, PRIMARY KEY (pk)); call set_table_property('tbl_col_row', 'orientation', 'row,column'); commit;
相關文檔
根據業務查詢場景設置合適的表屬性指南請參見場景化建表調優指南。