1. 程式人生 > >greenplum 表管理及檢視分割槽表佔空間大小

greenplum 表管理及檢視分割槽表佔空間大小

參考: http://www.xue5.com/Data/DataBase/693580.html

4.3. 管理表

或許你要說create table還要你在這邊指手畫腳的?其實不然,即使在Oracle裡面也還是有很多選項和引數未必都很清楚,何況是換了個不熟悉的gp,所以有必要全新的瞭解下。
建立表你需要考慮的內容和因素有:欄位型別、表或者欄位的約束、分佈策略、儲存策略、表分割槽等等。
4.3.0. 欄位型別
在gp中character型別的char、varchar、text之間在不考慮使用空格填充空白的情況下沒有區別,建議使用varchar和text替代char。而數字型別要考慮下型別大小佔用的空間問題了,BIGINT型別如果都是填充些INT或者SMALLINT型別的資料的話將會浪費空間。
4.3.1. 約束
欄位上,和oracle類似擁有primary、unique、check、not null、foreign約束,只是primary約束有個特殊的就是必須使用hash策略來分佈表資料儲存,不能在同一個表同時使用主鍵和唯一約束,並且指定了primary和unique的列必須全部或者部分包含在distributed key中;foreign約束雖然可以定義,但是並不會生效,至少在目前為止沒有支援。
4.3.2. 分佈策略
gp採用的是分佈存放資料的架構,有兩種分佈方式:distributed by (key),採用的是hash演算法,distributed randomly,採用的是隨機演算法;如果不指定分佈策略預設使用hash。
為了儘可能的並行處理資料,需要選擇能夠最大化地將資料均勻分佈到所有seg的策略,比如選擇primary key;分散式處理中將會存在本地和分散式協作的操作,當不同的表使用相同的分部鍵的時候,大部分的排序、連線關聯操作工作將會在本地完成,本地操作往往比分散式操作快上5倍,但是採用隨機分佈的策略無法享受到這個優勢。

預設情況下,不指定分佈策略將使用hash策略,並且選擇primiary key或者第1個column,key不能是幾何型別和使用者自定義的型別的column,如果沒有合適的列那麼會採用randomly策略。

4.3.3. blocksize設定
一個引數,可能不會經常用到的:block size介於8192和2097152之間,以byte為單位,即8k到2mb,預設32k。更大的塊大小會消耗更多的記憶體。
4.3.4. 資料儲存方式
gp提供了多種的資料儲存和組織方式,包括行儲存、列儲存、行和列混合儲存、壓縮、只讀表等等。
ao表只允許追加資料;列儲存只能是ao表;壓縮只使用與ao表;
4.3.4.0. heap堆表
最普通的表形式,適合於較小的、經常更新的資料儲存方式。
4.3.4.1. append only表

在某些情況下使用ao表存放非結構化的資料可以提高資料查詢效能,ao表不允許update和delete操作。

4.3.4.2. row or column oriented行或列表
從以下方面考慮如何選擇行或列儲存:
如果表資料在載入後必須update,那麼不能採用列儲存的表,列儲存只能適用於ao表;
如果表資料經常insert,還是建議採用行表,因為列表對寫入並沒有優勢,一列的資料必須往磁碟上寫入多個地方;
如果表的資料查詢經常是選擇多個列的查詢,建議使用行表,列表還是比較適合聚合查詢的場景,比如sum、avg等等;
如果一次查詢選擇了大部分的列或者行的資料相對小,採用行表,表的列數量如果非常多,那麼選擇行表是個不錯的建議;

因為列表中列的資料都是同一型別的,使用壓縮儲存可以比行表壓縮帶來更大的空間節省,帶來的問題是在讀取資料解壓縮的消耗,以及隨機訪問帶來的效能下降,壓縮只適用於ao表。

4.3.5. 壓縮表
可以基於表和行級別對資料進行壓縮,基於列級別的壓縮可以指定列和選擇不同的壓縮演算法。壓縮和解壓資料需要消耗更多的cpu資源,同時不要將資料儲存到壓縮的檔案系統中。壓縮資料初衷是出於最小化儲存空間,但是cpu消耗和壓縮速度同樣是重要的考慮因素
針對不同的組織方式的表有以下演算法選擇:
行表:可以選擇zlib和quicklz演算法,zlib有1-9個壓縮級別,級別越高壓縮比越高
列表:可以選擇zlib和quicklz以及rle_type演算法,rle_type是4.2.1之後版本新推出的稱為執行長度編碼的演算法,適合於有大量重複的資料記錄
quicklz通常比zlib更少的消耗cpu,更快的壓縮速度;在zlib壓縮級別1的情況之下,兩者通常具有相同的壓縮比,在級別大於6的情況下,會有更加顯著的壓縮比。


4.3.5.0. 列級別壓縮
只能適用於列儲存的表,可以在建立或修改表的語句中指定列壓縮命令。
C1 char ENCODING (compresstype=quicklz, blocksize=65536)   
COLUMN C1 ENCODING (compresstype=quicklz, blocksize=65536) 
DEFAULT COLUMN ENCODING (compresstype=quicklz) 

指定引數的生效優先順序如下(從高到底):分割槽表、分割槽、列,注意壓縮屬性不會被繼承,如果使用like子句建立的表會忽略列和表級別的引數

4.3.6. 臨時表
注意,臨時表是存放在一個特定的schema當中的,並不是當前預設的schema,而且可以建立2個臨時表和常規表公用一個名稱,但是預設訪問的是臨時表。臨時表有3個選項用來定義資料存活週期,on commit={preserve rows|delete rows|drop},預設是第1個。
4.3.7. 分割槽表
支援rang和list以及兩者混合的分割槽選項,無限制子分割槽層級數量;rang分割槽鍵只能有一個,適用於時間、數字範圍的分割槽,list可以有多個分割槽鍵,適用於字元值的分割槽。
使用時間分割槽的時候建議採用最細粒度的平面分割槽而不是多層級的分割槽,平面分割槽有更佳的查詢速度,多級分割槽有更好的查詢計劃分析時間。
分割槽表使用限制,分割槽鍵必須包含主鍵或者唯一鍵;
RAND範圍分割槽:
partiton by range(date) (start (date '2012-01-01') inclusive end (date '2015-01-01') exclusive,every(interval '1 month'))
LIST列表分割槽:
partiton by list(region) (partition prtusa values('usa'),partition prtchina values('chaina'),default prtother other)
分割槽的選擇性,查詢計劃只能對穩定的比較運算子執行選擇性掃描:= < <= > >= <>,不能選擇不穩定的函式,比如時間,但是可以對日期選擇比較。


4.3.8. 表使用匯總
--建立表 heap
gtlions=# create table t1(id int constraint pk_t1_id primary key using index tablespace gtlions_ts2,name text not null,age int constraint ck_t1_age check(age>=18),birth date not null,notes text default 'this is notes!') tablespace gtlions_ts1  distributed by (id);
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "t1_pkey" for table "t1"
CREATE TABLE


--建立臨時表 temporary
gtlions=# create temp table tp(id int) on commit delete rows;
NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'id' as the Greenplum Database data distribution key for this table.
HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew.
CREATE TABLE


--建立列表 column
gtlions=# create table t7 (id int) with(appendonly=true,orientation=column);                 
NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'id' as the Greenplum Database data distribution key for this table.
HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew.
CREATE TABLE


--建立只讀表 appendonly
gtlions=# create table t2(id int) with (appendonly=true) distributed by (id); 
CREATE TABLE


--建立壓縮表 compression
gtlions=# create table t3(id int,name text) with (appendonly=true,compresstype=zlib,compresslevel=9) distributed by (id);     
CREATE TABLE


gtlions=# create table t4(id int,name text,age date encoding(compresstype=quicklz),notes text ,column notes  encoding(compresstype=zlib,compresslevel=9),default column encoding(compresstype=quicklz,blocksize=8192)) with (appendonly=true,orientation=column);
NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'id' as the Greenplum Database data distribution key for this table.
HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew.
CREATE TABLE


--建立表 like
gtlions=# create table t5(like t4);
NOTICE:  Table doesn't have 'distributed by' clause, defaulting to distribution columns from LIKE table
CREATE TABLE


--建立表 as
gtlions=# create table t6 as select * from t4;
NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column(s) named 'id' as the Greenplum Database data distribution key for this table.
HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew.
SELECT 0


--建立按照數字分割槽,每個“1”一個分割槽,注意預設情況下start總是包含而end總是排除的
gtlions=# create table t9 (id int,name text) partition by range(id) (start (20) end (25) every(1),default partition prtdefault);    
NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'id' as the Greenplum Database data distribution key for this table.
HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew.
NOTICE:  CREATE TABLE will create partition "t9_1_prt_prtdefault" for table "t9"
NOTICE:  CREATE TABLE will create partition "t9_1_prt_2" for table "t9"
NOTICE:  CREATE TABLE will create partition "t9_1_prt_3" for table "t9"
NOTICE:  CREATE TABLE will create partition "t9_1_prt_4" for table "t9"
NOTICE:  CREATE TABLE will create partition "t9_1_prt_5" for table "t9"
NOTICE:  CREATE TABLE will create partition "t9_1_prt_6" for table "t9"
CREATE TABLE


--建立一個月份範圍分割槽
CREATE TABLE t10 (
    ID INT,
    DATE DATE,
    amt DECIMAL (10, 2)
) DISTRIBUTED BY (ID) PARTITION BY RANGE (DATE)(
    PARTITION Jan08 START (DATE '2008-01-01') INCLUSIVE,
    PARTITION Feb08 START (DATE '2008-02-01') INCLUSIVE,
    PARTITION Mar08 START (DATE '2008-03-01') INCLUSIVE,
    PARTITION Apr08 START (DATE '2008-04-01') INCLUSIVE,
    PARTITION May08 START (DATE '2008-05-01') INCLUSIVE,
    PARTITION Jun08 START (DATE '2008-06-01') INCLUSIVE,
    PARTITION Jul08 START (DATE '2008-07-01') INCLUSIVE,
    PARTITION Aug08 START (DATE '2008-08-01') INCLUSIVE,
    PARTITION Sep08 START (DATE '2008-09-01') INCLUSIVE,
    PARTITION Oct08 START (DATE '2008-10-01') INCLUSIVE,
    PARTITION Nov08 START (DATE '2008-11-01') INCLUSIVE,
    PARTITION Dec08 START (DATE '2008-12-01') INCLUSIVE END (DATE '2009-01-01') EXCLUSIVE
);


--建立一個list分割槽
gtlions=# create table t11 (id int,sex char) distributed by (id) partition by list (sex) (partition p_boy values('b'), partition p_girl values('g'),default partition uknow);
NOTICE:  CREATE TABLE will create partition "t11_1_prt_p_boy" for table "t11"
NOTICE:  CREATE TABLE will create partition "t11_1_prt_p_girl" for table "t11"
NOTICE:  CREATE TABLE will create partition "t11_1_prt_uknow" for table "t11"
CREATE TABLE


建立多層分割槽,多層分割槽會建立很多的子表,我們看下是如何計算一個分割槽表建立的子表的數量的,以下建立一個二級分割槽表,首先安裝月份分割槽,2013年一共12個月,然後按照地區分割槽:usa和chn、other3個分割槽:
create table t12 (id int,date date,region text) distributed by (id)
partition by range (date)
    subpartition by list (region)
    subpartition template 
    (
    subpartition prtregionusa values ('usa'),
    subpartition prtregionchn values ('china'),
    default subpartition prtregionother
    ) 
(start (date '2013-01-01') end (date '2014-01-01') every (interval '1 month'),default partition prtdataother);
首先sales本身會建立1父表,二級分割槽根據date會建立1*(12+1)個父表,同時也是region的父表,最後region一層不會子表,是根據上一層的date分割槽1*(12+1)*3個表,一共是1+1*(12+1)+1*(12+1)*3=53個表格。


--新增分割槽,只能在沒有預設分割槽的情況下新增新的分割槽,如果有預設分割槽而需要增加新的分割槽需要拆分分割槽操作
gtlions=# alter table t10  add partition jan09 start (date '2009-01-01') end (date '2009-02-01');          
NOTICE:  CREATE TABLE will create partition "t10_1_prt_jan09" for table "t10"
ALTER TABLE
--新增預設分割槽
gtlions=# alter table t10  add  default partition prtdef;                                                                                         
NOTICE:  CREATE TABLE will create partition "t10_1_prt_prtdef" for table "t10"
ALTER TABLE
--重新命名分割槽
gtlions=# alter table t10 rename partition for ('2008-01-01') to prt200801;
NOTICE:  renamed partition "jan08" to "prt200801" for relation "t10"
ALTER TABLE
gtlions=# alter table t10 rename partition for (rank(1)) to prt20080101;
NOTICE:  renamed partition "prt200801" to "prt20080101" for relation "t10"
ALTER TABLE
--拆分分割槽,將200901的資料當中的1-15日的資料拆分到新的分割槽,16-31的資料拆分到新的分割槽
gtlions=# alter table t10 split partition for ('2009-01-01') at ('2009-01-16') into (partition prt200901a,partition prt200901b);
NOTICE:  exchanged partition "jan09" of relation "t10" with relation "pg_temp_100487"
NOTICE:  dropped partition "jan09" for relation "t10"
NOTICE:  CREATE TABLE will create partition "t10_1_prt_prt200901a" for table "t10"
NOTICE:  CREATE TABLE will create partition "t10_1_prt_prt200901b" for table "t10"
ALTER TABLE
--拆分預設分割槽,將預設分割槽中的資料的200902的資料拆分出入形成一個新的分割槽,其餘資料還是存放在預設分割槽
gtlions=# alter table t10 split default partition start (date '2009-02-01') end (date '2009-03-01') into (partition prt200902,default partition);
NOTICE:  exchanged partition "prtdef" of relation "t10" with relation "pg_temp_100487"
NOTICE:  dropped partition "prtdef" for relation "t10"
NOTICE:  CREATE TABLE will create partition "t10_1_prt_prt200902" for table "t10"
NOTICE:  CREATE TABLE will create partition "t10_1_prt_prtdef" for table "t10"
ALTER TABLE
--刪除分割槽
gtlions=# alter table t10 drop partition for ('2009-01-01');
NOTICE:  dropped partition "prt200901a" for relation "t10"
ALTER TABLE
--刪除預設分割槽
gtlions=# alter table t10 drop default partition;
NOTICE:  dropped partition "prtdef" for relation "t10"
ALTER TABLE
--刪除分割槽表資料
loglap=# alter table t10 truncate partition for (rank(1));
ALTER TABLE
--交換分割槽資料
gtlions=# alter table t10 exchange partition for (rank(1)) with table t10a;
NOTICE:  exchanged partition "prt20080101" of relation "t10" with relation "t10a"
ALTER TABLE


--檢視分割槽資料分佈
gtlions=# select gp_segment_id,tableoid::regclass,count(*) from t10 group by 1,2 order by 1,2;     
 gp_segment_id | tableoid | count 
---------------+----------+-------
(0 rows)


4.3.8. 修改表
修改hash分佈策略會重新分佈資料,而randomly則不會重新分佈資料;當然我們也可以手工要求表重新分佈資料,這個操作在表資料分佈驗證傾斜或者增刪節點的情況下有用,這個操作對兩種分佈策略都是有效的;表的儲存模式是無法被修改的。
--修改分佈鍵
gtlions=# alter table t1 set distributed by (name);
ALTER TABLE
--手工重新分佈資料
gtlions=# alter table t1 set with (reorganize=true);
ALTER TABLE
--增改刪列
gtlions=# alter table t1 add column others text;
ALTER TABLE
gtlions=# alter table t1 alter column others type char(20);
ALTER TABLE
gtlions=# alter table t1 alter column others set default 'xx';    
ALTER TABLE
gtlions=# alter table t1 rename column others to o;
ALTER TABLE
gtlions=# alter table t1 drop column o;
ALTER TABLE
--修改約束
gtlions=# alter table t1 add constraint check_id check(id>=1);
ALTER TABLE
gtlions=# alter table t1 drop constraint check_id;
ALTER TABLE


-EOF-








參考: http://www.cnblogs.com/gobird/archive/2012/04/11/2442846.html

greenplum分割槽表檢視所佔空間大小

在使用greenplum資料庫的時候,有的時候想要查看錶所佔用空間的大小,會使用如下二個函式pg_relation_size和pg_size_pretty. 
前者用來檢視資料大小,後者是human readable的調整.方法如下:
select pg_size_pretty(pg_relation_size('relation_name')) ;
select pg_size_pretty(pg_relation_size(oid)) ;
但是,對於分割槽表而言,這個方法就沒有用了,會發現使用後表的大小為0bytes.原因在於:GP的分割槽表的主表只是一個表定義,其實際資料內容儲存在繼承父表的分割槽子表裡面了.上網查了一下,沒發現有相應的函式,乾脆寫了個函式來實現.
-- Function: calc_partition_table(character varying, character varying)
-- DROP FUNCTION calc_partition_table(character varying, character varying);
CREATE OR REPLACE FUNCTION calc_partition_table(v_schemaname character varying, v_tablename character varying)
  RETURNS bigint AS
$BODY$
DECLARE
    v_calc BIGINT := 0;
    v_total BIGINT := 0;
    v_tbname VARCHAR(200);
    cur_tbname cursor for select schemaname||'.'||partitiontablename as tb from pg_partitions
   where schemaname=v_schemaname and tablename=v_tablename;
BEGIN
    OPEN cur_tbname;
    loop
        FETCH cur_tbname into v_tbname;
        if not found THEN
            exit;
        end if;
        EXECUTE 'select pg_relation_size('''||v_tbname||''')' into v_calc;
        v_total:=v_total+v_calc;        
    end loop;
    CLOSE cur_tbname;
    RETURN v_total;
end;
$BODY$
  LANGUAGE plpgsql VOLATILE;
ALTER FUNCTION calc_partition_table(character varying, character varying) OWNER TO gpadmin;


--表佔用空間
SELECT relname as name, sotdsize/1024/1024 as size_MB, sotdtoastsize as toast, sotdadditionalsize as other
FROM gp_toolkit.gp_size_of_table_disk as sotd, pg_class
WHERE sotd.sotdoid = pg_class.oid 
ORDER BY relname;

--索引佔用空間
SELECT soisize/1024/1024 as size_MB, relname as indexname
FROM pg_class, gp_toolkit.gp_size_of_index
WHERE pg_class.oid = gp_size_of_index.soioid
AND pg_class.relkind='i';


select pg_size_pretty(pg_database_size('xxx'))


select * from pg_tables where schemaname='xxxx'
select oid,* from pg_namespace
select sum(relpages) from pg_class where relkind = 'i' and relnamespace=441490 
5704154
select sum(relpages) from pg_class where relkind = 'r' and relnamespace=441490 
21831261

select * from pg_class where relkind = 'r' and relnamespace=441490 and relname like 'tb%' order by relpages desc
"tb201302_sd";441490;24698109;10;0;28619180;0;717191;7.27088e+07;0;0;0;0;t;f;"r";"h";57;0;0;0;0;0;f;t;f;f;9290437;"";""

select pg_relation_size('"9960".tb201302_sd')/717191*27535415
715366760448
select pg_relation_size('"9960".tb201302_sd')/717191*5704154
186913718272

select pg_size_pretty(902280478720)--"666 GB"
select pg_size_pretty(186913718272)--"174 GB"

select sum(relpages) from pg_class where relnamespace=441490

27535415

select pg_size_pretty(pg_relation_size('"9960".tb201302_sd')) ;