533
技術社區[雲棲]
Greenplum列存壓縮表原理
用法
create table testao(id int, name text) with (APPENDONLY=true, ORIENTATION=column, COMPRESSTYPE=zlib, COMPRESSLEVEL=5, BLOCKSIZE=1048576, OIDS=false)
APPENDONLY=true, ORIENTATION=column這兩個屬性決定了這是列存壓縮表。
COMPRESSTYPE: 壓縮方式,支持zlip,RTE等
COMPRESSLEVEL: 壓縮級別,0-9
BLOCKSIZE: 塊大小8kB-2MB
優勢
- 節約成本,列存壓縮表空間占用遠小於普通的heap表空間
- 對查詢涉及的列很少時候,無需去讀其他列的數據,減少IO
- 追加寫速度快
存儲結構
總體方法是一個文件隻存一個列的值,一個文件由多個block組成。
- 組成結構
每個列占用一個至多個文件,最多128個,不同列的值不會同時出現一個文件。之所以這麼設計,是為了解決並發問題。
- block結構
struct getBlockInfo
{
int32 contentLen;
int execBlockKind;
int64 firstRow; /* is expected to be -1 for pre-4.0 blocks */
int rowCnt;
bool isLarge;
bool isCompressed;
} getBlockInfo;
BLOCKSIZE大小是8kB-2MB,由壓縮前的數據大小決定,壓縮後的block大小不一,其中block header不參與壓縮。如果插入的值超過blocksize,那麼數據將會拆成多個block;對於NULL值,block中使用bit位表示。
- RowNum機製
對於heap表,由tupleid決定每條記錄的位置(tupleid包含記錄在文件中偏移位置),而對於AO表,數據是壓縮的,沒法確定value在文件中偏移位置,因此引用了rownum,每條記錄都有自己的rownum,rownum一直增長,rownum可能不連續,但是沒關係,我們的block中記錄了起始rownum以及block在文件中偏移位置,所以隻要給我們一個rownum,我們就能定位到它所在的block,然後從block中就可以遍曆到這個rownum對應的記錄。
每次insert都會更新rownum,為了解決頻繁更新問題,每次申請100個rownum,批量insert時每100個才會更新rownum。通過select * from gp_fastsequence
可以查看已使用的rownum。
並發insert原理
當多個Session同時向表中insert數據時,如果隻有一個文件,那麼每次追加都需要對文件加鎖,顯然會降低插入性能,為了解決這個問題,當有並發insert時,每個session向各自對應的文件insert數據。不過最大的並發是128,單個列不能超過128個文件限製。
update/delete實現
delete和update不會在數據文件中直接更新或者刪除,而是使用一張heap輔助表visimap,包含一個bitmap列,通過select * from pg_appendonly
可以查看到,對任何一個數據的刪除直接在bitmap中標記一下即可。update是delete和insert兩步組合實現。
最後更新:2017-08-13 22:24:51