二維表同樣是GP中重要的存儲數據對象,為了更好的支持數據倉庫海量數據的訪問,GP的表可以分成:
- 面向行存儲的普通堆積表
- 面向列存儲的AOT表(append only table)
當然AOT表也可以是按行存儲的,但是按列存儲必須是AOT表。這樣,我們在設計應用上可以獲得相當的靈活性。比如經常需要更新的數據,或者較小的維度數據,應該使用普通堆積表存儲。
例子:
create table tmp_001( month_id numeric(8), serv_id numeric(30), cust_id numeric(30) ) with ( appendonly=true, compresslevel=5, orientation=column, compresstype=zlib, oids=false ) distributed by (month_id,serv_id)
1.分布鍵(哈希鍵)
- distributed by (a) 指定a字段為分布鍵
- distributer randomly 隨機分布
注意:
- 未指定分布鍵,默認表的主鍵為分布鍵,若表沒有主鍵,則默認把第一列當作哈希鍵
- 分布鍵可以被定義為一個或多個
- 分布鍵必須是唯一鍵
- 不能修改分布鍵,且哈希鍵的列不能update
- 一個表只能定義一個唯一鍵,且主鍵和唯一鍵必須作為哈希鍵
- 數值重復度低,保證數據均勻分布
- 防止數據傾斜,布爾值不適合,float、double數據類型也不適合,interger、varchar比較好
- 大表經常做連接時,選擇相同的分布鍵,避免跨節點進行join
- 盡量不用序列號,無意義
2.AOT 指定按列分布
- appendonly=true 指定是否只append追加
- compresslevel=5 zlib壓縮級別 1-9共9個級別 9壓縮最大
- orientation=column 指定是否按列存儲
- compresstype=zlib GP提供兩種壓縮算法:zlib和quicklz
- oids=false 對象標識符 不分配
3.其他注意
與其它數據庫相比,GP的表最大的不同是它一定是分區的,也就是表中的所有記錄都會依據相關算法打散,分布到所有的segment當中,從而在充分利用硬件資源的同時,最大化訪問數據的IO,這種特性對於數據倉庫應用是非常有幫助的。
GP提供兩種打散數據的算法,一種是Hash算法:distributed by (serv_id),在定義表的時候,通過distributed by指定表中的某個列或者某個列的組合作為Hash鍵,相同Hash鍵的記錄會放在同一個segment當中。所以,GP建議一般選擇記錄分布均勻的鍵作為Hash鍵使用,從而保證表中的記錄可以均勻分布到所有segment上。如果表上定義了主鍵或者唯一鍵,則這些鍵值列必須作前導列出現在分布鍵當中,並且放在第一位。
如果定義表的時候,沒有指定distributed子句,系統使用第一個列作為Hash鍵使用。
另一種數據打散的算法是平均分配法(ROUND-ROBIN),distributed randomly, 假設有三個段,那么這種算法會把第一條記錄放在段1, 第二條記錄放在段2,第三條記錄放在段3,第四條記錄放在段1,以此類推,直到所有記錄發放完為止。這種算法比較適合表中的字段存在嚴重數據傾斜的情況。
在數據倉庫中,對於存儲海量少變化歷史數據的事實表的訪問,會產生大量IO。這些表除了記錄多外(縱向),同時也很寬。比如幾十列,甚至上百列的表也很常見。但是在進行數據分析和挖掘過程中,我們可能只用到這些列的很小一部分內容,而傳統的按行存儲的表,在訪問時總是會訪問記錄中的所有列,導致很多無效IO,當由於表橫向尺寸過大,按行存儲的表還會出現行鏈接,這會使無效IO的問題更嚴重。在GP中,對於這種情況應該考慮使用面向列存儲的AOT表,從而大幅高IO效率,獲取數據查詢性能的收益。
現在硬件系統往往IO效率跟不上CPU處理的速度,而數據倉庫應用恰恰是IO敏感型的應用,所以很多數據倉庫系統上,會看到CPU很閑,但是出現大量IO等待的情況。所以通過壓縮,尤其是面向列壓縮,允許我們犧牲一定的CPU效率進一步換取IO效率,提高系統的的吞吐量。
GP的AOT表允許使用兩種壓縮算法,一種是ZLIB,它的壓縮率較高,對CPU的消耗較多,GP中可以指定1到9共9個級別。1的壓縮比最小,9最大。另一種算法是QUICKLZ,它的壓縮比小,能設置1,造成的CPU負載也比ZLIB小。
AOT表雖然查詢和加載數據的效率很高,但是如它的名字那樣它只能支持select,insert,truncate操作,不支持update和delete操作。所以它只適合存放經過處理基本最終無變化的歷史數據,用來提供高效的查詢訪問。
從數據數據存放的生命周期看,前面介紹的表都稱之為永久表,這些表的記錄不會因為事務的結束和會話的斷開而消失。而業務中,我們經常要使用到臨時數據集合,如果用永久表存放中間結果,一方面是在並發環境中數據不安全,另一方面頻繁的刪除表中的記錄或者刪除表,會導致大量碎片,在字典層面造成瓶頸。因此GP也支持臨時表,不同連接共享相同的表結構。比如下面的例子:
CREATE TEMP TABLE SALES_TMP (PROD_ID numeric NOT NULL , CUST_ID numeric NOT NULL , TIME_ID DATE NOT NULL , CHANNEL_ID numeric NOT NULL , PROMO_ID numeric NOT NULL , QUANTITY_SOLD numeric(10,2) NOT NULL , AMOUNT_SOLD numeric(10,2) NOT NULL) on commit preserve rows distributed randomly;
CREATE TEMP TABLE SALES (PROD_ID numeric NOT NULL , CUST_ID numeric NOT NULL , TIME_ID DATE NOT NULL , CHANNEL_ID numeric NOT NULL , PROMO_ID numeric NOT NULL , QUANTITY_SOLD numeric(10,2) NOT NULL , AMOUNT_SOLD numeric(10,2) NOT NULL) on commit delete rows distributed by (prod_id,cust_id,time_id,channel_id,promo_id);
例子一是事務內有效,連接會話間數據獨立。完成事務后數據保留,只有連接會話斷開后數據才消失。
例子二是事務內有效,也就是提交事務后(commit)數據就會消失。
如果臨時表的名字與永久表名字重復,臨時表的訪問優先。
除了普通表以外,GP還支持超大表進行分區應用,為我們的提高數據訪問效率的同時,也提高應用的靈活型。它可以支持RANGE分區,LIST分區,以及靈活的復合分區(RANGE-LIST,RANGE-RANGE,LIST-RANGE,LIST-LIST,以及更多層次的分區,比如三層分區),GP的分區是基於segment基礎之上的。每個分區的數據同樣會打散分布到每個segment中,當where條件上出現分區鍵時,它會進行分區裁剪,減少IO。需要注意的是,目前GreenPlum還只支持靜態分區裁剪,所以如果希望用到分區裁剪,請在Where條件中使用事實表的分區鍵作為條件。
END 2018-08-01 18:17:13