5 常見建立TABLE方式
5 常見建立TABLE方式
5.1 建立Heap表
drop table if exists test_head;
create table test_head(id int primary key) distributed by (id);
distributed by 表示制定分佈鍵,便於segment儲存資料
5.2 建立AO表
5.2.1 AO表不壓縮
drop table if exists test_ao;
create table test_ao(id int) with (appendonly=true) distributed by (id);
appendonly=true是表示AO(Append-optimized)儲存表的表示,引數為true和false,例如appendonly=true或appendonly=false
5.2.2 AO表壓縮
drop table if exists test_ao;
create table test_ao(id int) with (appendonly=true, compresslevel=5) distributed by (id);
compresslevel是壓縮率,取值為1~9,一般選擇5就足夠了,值越高壓縮率越高
5.2.3 AO表列存壓縮
AO表列存壓縮 與上表的壓縮方式不同
drop table if exists test_ao;
create table test_ao(id int) with (appendonly=true,compresslevel=5, orientation=column) distributed by (id);
orientation是對列進行壓縮,寫法只有orientation=column
5.2.3.1 對orientation引數進行測試
5.2.3.1.1 建立表語句
建立不對列壓縮的表
CREATE TABLE e_alter_recoder_out_20180810(
s_ext_nodenum varchar ,
pripid varchar ,
s_ext_sequence varchar ,
alt_id varchar ,
altitem varchar ,
altbe varchar,
altaf varchar,
altdate varchar ,
alttime varchar ,
s_ext_timestamp varchar ,
s_ext_batch varchar ,
s_ext_validflag varchar,
jobid varchar,
entid varchar,
handle_type varchar
) WITH (appendonly=true, compresstype=zlib, compresslevel=5)
DISTRIBUTED BY (pripid);
建立對列壓縮的表
CREATE TABLE e_alter_recoder_out_20180812(
s_ext_nodenum varchar ,
pripid varchar ,
s_ext_sequence varchar ,
alt_id varchar ,
altitem varchar ,
altbe varchar,
altaf varchar,
altdate varchar ,
alttime varchar ,
s_ext_timestamp varchar ,
s_ext_batch varchar ,
s_ext_validflag varchar,
jobid varchar,
entid varchar,
handle_type varchar
) WITH (appendonly=true, compresstype=zlib, compresslevel=5,orientation=column)
DISTRIBUTED BY (pripid);
在以上可以看出一共有15個欄位
5.2.3.1.2 檢視資料的大小
$ du -sh mv_e_alter_recoder_20180922.csv
48G mv_e_alter_recoder_20180922.csv
5.2.3.1.3 使用COPY命令匯入資料
$ time psql -d stagging -h 192.168.209.11 -p 5432 -U gpadmin -c "\COPY e_alter_recoder_out_20180810 FROM '/data/oracle-export-data/DATA20180922/mv_e_alter_recoder_20180922.csv' WITH csv DELIMITER E'\001' LOG ERRORS SEGMENT REJECT LIMIT 3000 ROWS"
Password for user gpadmin:
real 11m49.978s
user 1m17.379s
sys 0m43.668s
time psql -d stagging -h 192.168.209.11 -p 5432 -U gpadmin -c "\COPY e_alter_recoder_out_20180812 FROM '/data/oracle-export-data/DATA20180922/mv_e_alter_recoder_20180922.csv' WITH csv DELIMITER E'\001' LOG ERRORS SEGMENT REJECT LIMIT 3000 ROWS"
Password for user gpadmin:
real 12m11.227s
user 1m27.575s
sys 0m50.548s
在以上結果中可以看出不對列壓縮用時11m49.978s,而對列壓縮的用時12m11.227s,相差23S
5.2.3.1.4 檢視在資料庫中佔用的大小
select pg_size_pretty(pg_relation_size('e_alter_recoder_out_20180810'));
-- 14 GB
select pg_size_pretty(pg_relation_size('e_alter_recoder_out_20180812'));
-- 11 GB
使用列壓縮竟然縮小了3G的空間,好恐怖,23S節省3G空間,值得擁有。
5.2.3.1.5 查看錶的行數
select count(*) from e_alter_recoder_out_20180810;
-- 156784862
select count(*) from e_alter_recoder_out_20180812;
-- 156784862
5.2.3.2 統計壓縮的大小
5.2.3.2.1 原始表佔用大小
查詢各個schema佔用大小的SQL:
select pg_size_pretty(cast(sum(pg_relation_size( schemaname || '.' || tablename)) as bigint)), schemaname from pg_tables t inner join pg_namespace d on t.schemaname=d.nspname group by schemaname;
schema下有750張佔用940GB的空間,原始壓縮方式為:WITH (appendonly=true, compresstype=zlib, compresslevel=5)
5.2.3.2.2 壓縮後表的佔用大小
修改壓縮方式後:WITH (appendonly = true, compresstype = zlib, compresslevel = 7
,orientation=column, checksum = false,blocksize = 2097152),具體的引數的含義請參考以上的說明。
在以上可以看出已經節省了320GB的空間,又省錢可以買糖吃啦,別拉我,我要去買糖、、、
5.2.3.3 壓縮型別比較
5.2.3.3.1 檢視壓縮前的大小
以下表的引數為:
with ( appendonly = true, compresstype = zlib, compresslevel = 7
,orientation=column, checksum = false,blocksize = 2097152 )
stagging=# select pg_size_pretty(pg_relation_size('xiaoxu.e_alter_recoder_out_20180810_com'));
pg_size_pretty
----------------
11 GB
(1 row)
Time: 33.880 ms
使用compresstype = zlib的壓縮方式的大小為 11 GB,修改compresstype 的引數檢視大小,其中引數為:zlib,quicklz,rle_type
5.2.3.3.2 使用quicklz壓縮
stagging=# create table xiaoxu.e_alter_recoder_out_20180810_com_quicklz with (appendonly = true, compresstype = quicklz, compresslevel = 1 ,orientation=column, checksum = false,blocksize = 2097152) as select * from xiaoxu.e_alter_recoder_out_20180810_com Distributed by (pripid);
SELECT 156784862
Time: 59158.322 ms
stagging=# select pg_size_pretty(pg_relation_size('xiaoxu.e_alter_recoder_out_20180810_com_quicklz'));
pg_size_pretty
----------------
14 GB
(1 row)
Time: 34.632 ms
在以上看出使用quicklz壓縮直接蹦到14GB了,不可忍受
5.2.3.3.3 使用rle_type壓縮
stagging=# create table xiaoxu.e_alter_recoder_out_20180810_com_rle_type with (appendonly = true, compresstype = rle_type, compresslevel = 1 ,orientation=column, checksum = false,blocksize = 2097152) as select * from xiaoxu.e_alter_recoder_out_20180810_com Distributed by (pripid);
SELECT 156784862
Time: 124042.881 ms
stagging=# select pg_size_pretty(pg_relation_size('xiaoxu.e_alter_recoder_out_20180810_com_rle_type'));
pg_size_pretty
----------------
38 GB
(1 row)
Time: 10.006 ms
這個更厲害,已經飆到38GB了,嚇得我趕緊刪除了,爬伺服器冒煙、、
5.3 建立HDFS外表例項
5.3.1 建立外部表例項
CREATE EXTERNAL TABLE e_alter_recoder_out_20180812(
s_ext_nodenum varchar ,
pripid varchar ,
s_ext_sequence varchar ,
alt_id varchar ,
altitem varchar ,
altbe varchar,
altaf varchar,
altdate varchar ,
alttime varchar ,
s_ext_timestamp varchar ,
s_ext_batch varchar ,
s_ext_validflag varchar,
jobid varchar,
entid varchar,
handle_type varchar )
LOCATION ('gphdfs://nameservice1/tmp/e_alter_recoder_20180812/E_ALTER_RECODER/*') format 'text' (delimiter E'\u0001' FILL MISSING FIELDS) NULL as 'null string' ESCAPE as 'OFF' LOG ERRORS SEGMENT REJECT LIMIT 3000 ROWS;
EXTERNAL外表需要新增關鍵字
nameservice1是HDFS的HA的地址,需要先配置好,或者寫成192.168.209.105:8090
tmp/e_alter_recoder_20180812/E_ALTER_RECODER/是HDFS上的路徑
delimiter分隔符是 E'\u0001',也就是隱藏符SOH
LOG ERRORS SEGMENT REJECT說明吧錯誤資料放到GP預設的gp_read_error_log中
LIMIT 3000 ROWS 表示允許錯誤的最大的錯誤數,可以調大也可以調小,最小為2
5.3.2 檢視錯誤資料的例項
SELECT gp_read_error_log('tableName');
錯誤表字段解釋:
Column | Type | Modifiers
----------+--------------------------+-----------
cmdtime | timestamp with time zone | --操作時間
relname | text | --表名
filename | text | --檔名
linenum | integer | --錯誤行號
bytenum | integer |
errmsg | text | --錯誤資訊
rawdata | text | --整行資料
rawbytes | bytea | --行大小
Distributed randomly
詳細的說明請檢視:Greenplum載入資料常見錯誤及解決方法
5.3.3 建立可寫外部表例項
5.3.3.1 建立可寫外部表例項
CREATE WRITABLE EXTERNAL TABLE table_name
( column_name data_type [, ...] | LIKE other_talbe )
LOCATION ('gpfdist://outputhost[:port]/fillename'[, ...]) | ('gpfdist://hdfs_host[:port]/path')
FORMAT 'TEXT'
[( [DELIMITER [AS] 'delimiter']
[NULL [AS] 'null string']
[ESCAPE [AS] 'escape' | 'OFF'] )]
| 'CSV'
[([QUETE [AS] 'quote']
[DELIMITER [AS] 'delimiter']
[NULL [AS] 'null string']
[FORCE QUOTE column [, ...]]
[ESCAPE [AS] 'escape'] )]
[ ENCODING 'write_encoding' ]
[DISTRIBUTED BY (column, [ ... ] ) | DISTRIBUTED RANDOMLY]
5.3.3.2 建立可寫外部表
stagging=# drop external table xiaoxu.hdfs_writable_test;
DROP EXTERNAL TABLE
Time: 85.875 ms
stagging=# CREATE WRITABLE EXTERNAL TABLE xiaoxu.hdfs_writable_test (LIKE xiaoxu.e_alter_recoder_out_20180810
) LOCATION ('gphdfs://nameservice1/tmp/xiaoxu/hdfs_writable_test'
) format 'text' (DELIMITER E'\u0001' NULL as 'null string' ESCAPE as 'OFF'
) Distributed by (pripid);
Time: 55.628 ms
stagging=# insert into xiaoxu.hdfs_writable_test select * from xiaoxu.e_alter_recoder_out_20180810 limit 10;
INSERT 0 10
Time: 1582.187 ms
xiaoxu.hdfs_writable_test : 表明
tmp/xiaoxu/hdfs_writable_test : HDFS上路徑的名字
在以上可以看出只需要WRITABLE 關鍵字既可以實現外部表
5.3.3.3 檢視HDFS上的資料
在以上中可以看出HDFS已經正確的分割了資料
5.4 建立分割槽表
5.4.1 分割槽表概念
分割槽表意思是將一個大表在物理上分割成幾塊,GPDB中的分割槽表和PostgreSQL中實現原理一樣,都是用過表繼承、約束來實現。但是與PostgreSQL也有所不同,在PostgreSQL中,一個父表,多個子表來實現分割槽表,需要手動向子表插入資料,如果向父表插入資料,則直接會被插入到父表中,在GPDB中,可以直接想父表插入資料,便可以根據約束直接自動向對應的子表插入資料,當分割槽子表不存在時,插入失敗。
5.4.2 建立分割槽表
drop table if exists t05;
create table t05(id int, createOn date) with (appendonly=true, compresslevel=5,orientation=column) distributed by (id)
Partition By Range(createOn)(
partition p2016 start ('2016/01/01'::date) inclusive end ('2016/12/31'::date) exclusive,
partition p2017 start ('2017/01/01'::date) inclusive end ('2017/12/31'::date) exclusive,
partition p2018 start ('2018/01/01'::date) inclusive end ('2018/12/31'::date) exclusive
-- default partition otherTime
);
Range 分割槽表的關鍵字
p2016 分割槽表的名稱
start 開始分割槽表的開始時間
end 分割槽表的結束時間
default partition otherTime 也可以使用預設的分割槽
inclusive:指定包含,例如上面的 start ('2016/01/01') inclusive 則是包含'2016/01/01'
exclusive:指定不包含, 例如上面的 end ('2016/12/31') exclusive 則是不包含'2016/12/31'
5.4.3 檢視建立的分割槽表
5.4.3.1 檢視建立表的名稱
可以看出GP已經把分割槽的字首給設定好了,t05_1_prt_p2016,p2016即使當前分割槽的名字
5.4.3.2 查看錶的結構
stagging=# \d+ t05_1_prt_p2016
Append-Only Columnar Table "public.t05_1_prt_p2016"
Column | Type | Modifiers | Storage | Compression Type | Compression Level | Block Size | Description
----------+---------+-----------+---------+------------------+-------------------+------------+-------------
id | integer | | plain | zlib | 5 | 32768 |
createon | date | | plain | zlib | 5 | 32768 |
Checksum: t
Check constraints:
"t05_1_prt_p2016_check" CHECK (createon >= '2016-01-01'::date AND createon < '2016-12-31'::date)
Inherits: t05
Has OIDs: no
Options: appendonly=true, compresslevel=5, orientation=column
Distributed by: (id)
在以上的資訊中可以看出分割槽表其實就是主表管理者分割槽表的一個約束範圍,partition p2016 start ('2016/01/01'::date) end ('2016/12/31'::date)
寫法表示createon >= '2016-01-01'::date AND createon < '2016-12-31'::date的範圍,分佈鍵與主表的分佈鍵一致
5.4.4 插入分割槽表資料
5.4.4.1 生成資料指令碼
$ cat date_partition.sh
#!bin/bash
# $1 是開始時間
# $2 是結束時間
# $3 生成資料儲存的檔案
begin_date=$1
end_date=$2
while [ "$begin_date" != "$end_date" ]
do
echo $begin_date"|"$begin_date >> $3
let begin_date=`date -d "-1 days ago ${begin_date}" +%Y%m%d`
done
5.4.4.2 插入資料
在插入資料時只需要向主表中插入資料即可
$ psql -d stagging -h 192.168.209.11 -p 5432 -U gpadmin -c "\COPY t05 FROM '/home/*******/partition_data/20161231.csv' WITH csv DELIMITER '|' LOG ERRORS SEGMENT REJECT LIMIT 5000 ROWS"
如果插入一個沒有分佈表的會報一下錯誤資訊
$ psql -d stagging -h 192.168.209.11 -p 5432 -U gpadmin -c "\COPY t05 FROM '/home/******/partition_data/20191231.csv' WITH csv DELIMITER '|' LOG ERRORS SEGMENT REJECT LIMIT 5000 ROWS"
NOTICE: Found 364 data formatting errors (364 or more input rows). Rejected related input data
5.4.5 檢視資料及資料分佈情況
5.4.5.1 檢視主表的資料
select * from t05 where id BETWEEN '20160101' AND '20181231'
5.4.5.2 檢視分佈表的資料
select * from t05_1_prt_p2016;
5.4.5.3 檢視資料分佈情況
檢視分割槽表的分佈情況
select gp_segment_id,count(1) from t05_1_prt_p2016 group by 1;
檢視主表的分佈情況
select gp_segment_id,count(1) from t05 group by 1;
5.4.6 對分割槽表常用操作
5.4.6.1 增加分割槽
ALTER TABLE t05 ADD PARTITION p2019
START (date '2019/01/01') END (date '2019/12/31') EXCLUSIVE;
5.4.6.2 刪掉分割槽
alter table t05 drop partition p2016;
5.4.6.3 清空分割槽
相當於DROP掉又重新建立的分割槽
alter table t05 truncate partition p2016;
5.4.6.4 修改分割槽
alter table t05 split partition p2019 at ('2019-06-30') into (partition p2019, partition p2020);
5.4.6.5 修改default分割槽
alter table t05 split default partition start ('2017-03-01') end ('2017-03-31') into (partition p4, default partition);
5.4.7 建立數字範圍的分割槽表
drop table if exists t06;
create table t06(id int,dayOfPeriod int) distributed by (id)
partition by range(dayOfPeriod)
(
start (1) end (31) every(1),
default partition none
);
every 表示每次增加一,可以拿此作為主鍵
5.4.8 建立字母範圍的分割槽表
drop table if exists t07;
create table t07(id int , gender char(2)) with(appendonly=true,compresslevel=5) distributed by (id)
partition by list(gender)
(
partition man values('m'),
partition woman values('f'),
default partition Unkown
);
5.5 快速複製表
CREATE TABLE e_alter_recoder_out_20180814 WITH (
appendonly = TRUE,
compresstype = zlib,
compresslevel = 5,
orientation = column
) AS SELECT
*
FROM
e_alter_recoder_out_20180812 Distributed BY (pripid)
檢視執行的執行的時間
**************
FROM
e_alter_recoder_out_20180812 Distributed BY (pripid)
時間: 69.977s
受影響的行: 1,5678,4862
可以看出14 GB的檔案用時 69.977s匯入1,5678,4862行的資料