Greenplum 存儲及使用場景

Greenplum支持行存和列存,對應的是堆表和AO表

行存和列存的原理

1、行存,以行爲形式組織存儲,

查詢的時候需要全表掃描要掃描更多的數據塊;壓縮比較低;讀取任意列的成本不一樣,越靠後的列,成本越高。

2、列存,以列爲形式組織存儲,每列對應一個或一批文件。讀取任一列的成本是一樣的,但是如果要讀取多列,需要訪問多個文件,訪問的列越多,開銷越大

壓縮比高;讀取任意列的成本是一樣的;非常適合向量計算、JIT架構。對大批量數據的訪問和統計,效率更高;讀取很多列時,由於需要訪問更多的文件,成本更高

存儲格式介紹

Greenplum(以下簡稱GP)有2種存儲格式,Heap表和AO表(AORO表,AOCO表)。

  • Heap表:這種存儲格式是從PostgreSQL繼承而來的,目前是GP默認的表存儲格式,只支持行存儲。
  • AO表: AO表最初設計是隻支持append的(就是隻能insert),因此全稱是Append-Only,在4.3之後進行了優化,目前已經可以update和delete了,全稱也改爲Append-Optimized。AO支持行存儲(AORO)和列存儲(AOCO)。

Heap表

Heap表是從PostgreSQL繼承而來,使用MVCC來實現一致性。如果你在創建表的時候沒有指定任何存儲格式,那麼GP就會使用Heap表。

Heap表支持分區表,只支持行存,不支持列存和壓縮。需要注意的是在處理update和delete的時候,Heap表並沒有真正刪除數據,而只是依靠version信息屏蔽老的數據,因此如果你的表有大量的update或者delete,表佔用的物理空間會不斷增大,這個時候需要依靠vacuum來清理老數據。

Heap表不支持邏輯增量備份,因此如果要對Heap表做快照,每次都需要導出全量數據。

建表語句

CREATE TABLE heap( a int, b varchar(32) ) DISTRIBUTED BY (a);

最佳實踐:

  • 如果該表是一張小表,比如數倉中的維度表,或者數據量在百萬以下,推薦使用Heap表。
  • 如果該表的使用場景是OLTP的,比如有較多的update和delete,查詢多是帶索引的點查詢等,推薦使用Heap表。

AO表

AO表是GP特有的,設計的目的就是爲了數倉中大型的事實表。AO表支持行存和列存,並且也支持對數據進行壓縮。

AO表無論是在表的邏輯結構還是物理結構上,都與Heap表有很大的不同。比如上文所述Heap表使用MVCC控制update和delete之後數據的可見性,而AO表則使用一個附加的bitmap表來實現,這個表的的內容就是表示AO表中哪些數據是可見的。

對於有大量update和delete的AO表,同樣需要vacuum進行維護,不過在AO表中,vacuum需要對bitmap進行重置並壓縮物理文件,因此通常比Heap的vacuum要慢。

AORO表

AORO就是行存的AO表,同時行存也是AO表的默認存儲方式。

AORO支持表級別的壓縮,不支持列級別的壓縮。

建表語句如下,重點是with後的appendonly=true,由於AO表默認是行存,因此orientation=row也可以不要,後面的compresstype=zlib, compresslevel=4都是壓縮相關選項。

CREATE TABLE aoro( a int, b int, c varchar(32), d varchar(32) ) WITH (appendonly=true, orientation=row, compresstype=zlib, compresslevel=4) DISTRIBUTED BY (a)

壓縮選項:

  • compresstype :壓縮格式,開源版本的AORO表只支持zlib。
  • compresslevel :壓縮級別,從1-9,簡單說來,級別越低(1最低),壓縮比越低,但是壓縮與解壓消耗的cpu資源就越少。默認壓縮級別是1。

最佳實踐______:

  • AO表主要是針對大表,比如數倉中的事實表。
  • AO表支持邏輯增量備份,對於比較大的表,如果需要定期做快照,建議使用AO表,否則每次都要導出全量數據。
  • 如果該表是大表,使用場景偏OLTP並且update和delete頻率不高,可以考慮使用AORO表。
  • 如果該表是大表,並且查詢通常都需要掃描大多數列比如查詢明細(最典型的就是SELECT * FROM),可以考慮使用AORO表。
  • 在設置壓縮級別的時候,通常對於Snova用戶,設置到4或者5是比較折中的一個選擇。

AOCO表

AOCO表就是列存的AO表。

AOCO不僅支持表級別的壓縮,同時也支持列級別的壓縮。

CREATE TABLE aoco( a int ENCODING (compresstype=zlib, compresslevel=5), b int ENCODING (compresstype=none), c varchar(32) ENCODING (compresstype=RLE_TYPE, blocksize=32768), d varchar(32), fdate date ) WITH (appendonly=true, orientation=column, compresstype=zlib, compresslevel=6, blocksize=65536) DISTRIBUTED BY (a) PARTITION BY RANGE(fdate) ( PARTITION pn START ('2018-11-01'::date) END ('2018-11-10'::date) EVERY ('1 day'::interval), DEFAULT PARTITION pdefault );

壓縮選項:

  • compresstype:支持2種壓縮格式,zlib和RLE_TYPE,其中RLE_TYPE(Run-length Encoding)對於有較多重複值的列壓縮比很高,因爲它會將多個重複值存儲爲一個值,從而大大降低存儲量,比如日期,性別,年齡等字段。
  • compresslevel:compresstype如果是zlib,compresslevel在1-9,compresstype如果是RLE_TYPE,compresslevel在1-4。
  • 列壓縮與表壓縮:AOCO表除了支持表級別的壓縮外,還支持列級別的壓縮,列級別的壓縮配置會覆蓋表級別的壓縮配置,比如上述語法中4個字段,每個字段都採用了不用的壓縮方式,d列沒有定義,則會默認使用表級別的壓縮方式。
  • 分區壓縮:在使用分區表的時候,每個分區表也可以設置不同的壓縮配置,這個常用於對數據進行冷熱分離,比如對於非常老的數據,由於訪問頻率較低,可以考慮採用較大的壓縮比,減少存儲量。

BLOCKSIZE:

  • 表的存儲塊大小,通常表數據對應的物理文件就是按blocksize的粒度增加,也就是初始就是blocksize大,並且保持blocksize的倍數。
  • blocksize大小在8192和2097152之間,必須是8192的倍數,默認是32768。
  • 在AOCO表中,每一列也可以設置自己的blocksize,列的配置會覆蓋表的配置。

物理文件:

  • AOCO表之所以能夠按照列來設置壓縮等參數,本質原因在於AOCO表中每一列的數據都會單獨存儲在一個文件中。因此不同文件之間可以按不同的參數進行存儲,互不影響。
  • 對於AOCO表,如果使用了分區,那麼對於每一個分區的每一列都會有一個文件,如果一個表的分區很多,又是一張大寬表,那麼產生的文件就會很多,也會對性能有一些影響。

最佳實踐:

  • AOCO表通常用於數倉中的核心事實表,這種表字段多,數據量大,主要是用於OLAP場景,也就是查詢的過程不會SELECT * FROM,而是對其中部分字段進行讀取和聚合。
  • 由於AOCO表一般用於大表,因此經常搭配壓縮和分區,以減少表的實際存儲量來提升性能。
  • 一般情況下,壓縮格式選擇zlib,壓縮級別可以採用折中的4或者5,但是對於有大量重複值的字段,記得要採用RLE_TYPE壓縮格式。
  • blocksize不要設置過大,特別是對於分區表,GP對於每個分區的每個字段都會維護一個buffer,blocksize過大,會導致消耗的內存過大,通常就採用默認值32768即可。

修改表結構

單獨列出這一節是因爲Heap,AORO和AOCO這3種表在修改表結構時表現是不一樣的,這也是大家容易忽視的地方。

對於不同的表類型,同樣的修改語法耗時可能會差異很多,主要原因在於對於有些修改操作會導致表重寫,而表重寫的時間就取決於表本身的數據量。

混合存儲

一張表是否可以同時使用多種存儲方式呢?對於分區表,是可以的。

混合存儲一般用於這樣的場景,對於一張按時間分區的表,通常對於不同時間點的數據行爲是不一樣的,比如對於最近的數據,會有較多的明細查詢,而對於比較老的數據,則是以分析爲主。同時由於業務可能要保存較長時間的數據,爲了節約成本,較老的數據會考慮使用壓縮比較大的存儲方式。

混合存儲的關鍵就是使用到了GP的交換分區語法,也就是將一張獨立的表與自己的一個分區表進行交換,當然這裏前提是新表的結構是一樣,並且交換的過程沒有新數據進入。

流程如下:

1.創建一張分區表(1到5月份,每月一張表),採用Heap存儲

CREATE TABLE hyper_storage ( a int, b varchar(32), fdate date ) DISTRIBUTED BY (a) PARTITION BY RANGE(fdate) ( PARTITION pn START ('2018-01-01'::date) END ('2018-06-01'::date) EVERY ('1 month'::interval), DEFAULT PARTITION pdefault ); storage=# \d List of relations Schema | Name | Type | Owner | Storage --------+------------------------------+-------+--------------+--------- public | hyper_storage | table | test | heap public | hyper_storage_1_prt_pdefault | table | test | heap public | hyper_storage_1_prt_pn_1 | table | test | heap public | hyper_storage_1_prt_pn_2 | table | test | heap public | hyper_storage_1_prt_pn_3 | table | test | heap public | hyper_storage_1_prt_pn_4 | table | test | heap public | hyper_storage_1_prt_pn_5 | table | test | heap

2.現在要對1月份的表修改存儲格式,因此創建一張新的AOCO表

CREATE TABLE exchange_table( a int, b varchar(32), fdate date ) WITH (appendonly=true, ORIENTATION=column, compresstype=zlib, compresslevel=6) DISTRIBUTED BY (a)

3.將1月份的數據導入新表

INSERT INTO exchange_table SELECT * FROM hyper_storage_1_prt_pn_1;

4.交換分區

ALTER TABLE hyper_storage EXCHANGE PARTITION pn_1 WITH TABLE exchange_table;

注:pn_1是1月份的分區表的partitionname,可以從pg_partitions中查詢得到

5.查看結果

storage=# \d List of relations Schema | Name | Type | Owner | Storage --------+------------------------------+-------+--------------+---------------------- public | hyper_storage | table | test | heap public | hyper_storage_1_prt_pdefault | table | test | heap public | hyper_storage_1_prt_pn_1 | table | test | append only columnar public | hyper_storage_1_prt_pn_2 | table | test | heap public | hyper_storage_1_prt_pn_3 | table | test | heap public | hyper_storage_1_prt_pn_4 | table | test | heap public | hyper_storage_1_prt_pn_5 | table | test | heap public | exchange_table | table | test | heap

這樣1月份的分區表就變成了AOCO表,而其他分區表仍然是Heap表

選取Heap,AORO,AOCO三種表,分別採用壓縮和不壓縮2種方式(Heap表不支持壓縮,AO表壓縮採用zlib格式,壓縮級別設置爲6),插入5億條隨機數據,然後使用

select pg_size_pretty(pg_relation_size('{tablename}'));

Heap表佔用空間更大,即使AO表不採用壓縮。AOCO表由於是按列進行存儲,所以相比行存的AORO表壓縮比更大。當然這三者的差距取決於數據的實際情況,一般生產環境中Heap表不會和AO表有如此大的差距。

 

使用AOCO表,zlib壓縮格式,選取不同的壓縮級別,比較數據寫入時間和表所佔大小,由於zlib支持9個級別,這裏選取1,6,9 三個級別進行比較,體現出趨勢即可。實際生產環境中不同壓縮級別的數據,壓縮比的差距可能會更大。但可以看出,越高的壓縮級別,在插入的時候越耗時,其它SQL,類似SELECT,UPDATE等也都是一樣。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章