1. 程式人生 > >GreenPlum資料載入方式總結

GreenPlum資料載入方式總結

在GreenPlum中有以下幾種方式來進行資料的載入,包括

  1. 通過insert命令來實現少量資料的匯入;
  2. 通過copy命令來實現資料的匯入匯出;
  3. 通過建立外部表及gpfdist實現資料的匯入匯出;
  4. 通過gpload實現資料的匯入;

下面將分別介紹這幾種資料載入方式。

insert命令

通過簡單的insert語句來實現,常用於少量資料的匯入,當資料量較大時,會很耗時,從而不適合使用。

insert into tablename values('data');

copy命令

對於資料載入,GreenPlum資料庫提供copy工具,copy工具源於PostgreSQL資料庫,copy命令支援檔案與表之間的資料載入和表對檔案的資料解除安裝。使用copy命令進行資料載入,資料需要經過Master節點分發到Segment節點,同樣使用copy命令進行資料解除安裝,資料也需要由Segment傳送到Master節點,由Master節點彙總後再寫入外部檔案。這樣就限制了資料載入與解除安裝的效率,但是資料量較小的情況下,copy命令就非常方便。

資料載入
建立表&準備測試資料
lottu=# create table tbl_pay_log_copy (id int primary key,order_num varchar(100),accountid varchar(30),qn varchar(20),appid int,amount numeric(10,2),pay_time timestamp);

lottu=# \d tbl_pay_log_copy
           Table "public.tbl_pay_log_copy"
  Column   |            Type             | Modifiers 
-----------+-----------------------------+-----------
 id        | integer                     | not null
 order_num | character varying(100)      | 
 accountid | character varying(30)       | 
 qn        | character varying(20)       | 
 appid     | integer                     | 
 amount    | numeric(10,2)               | 
 pay_time  | timestamp without time zone | 
Indexes:
    "tbl_pay_log_copy_pkey" PRIMARY KEY, btree (id), tablespace "tbs_lottu"
Distributed by: (id)
Tablespace: "tbs_lottu"

[
[email protected]
~]$ head ios_pay.txt 73,ysios_receipt_3793615cb10dc393bba87c82d3c6544f,27388062,yriu1244_16043_001,2616,98.00,2017-11-06 17:36:43 72,ysios_receipt_32946f3d37e774781babe103352bd230,27424976,yriu1244_16043_001,2616,30.00,2017-11-06 15:18:56 75,ysios_receipt_3e2e432550253450412692392c7675d0,27388294,yriu1244_16043_001,2616,98.00,2017-10-19 07:33:03 74,ysios_receipt_3793615cb10dc393bba87c82d3c6544f,27388062,yriu1244_16043_001,2616,98.00,2017-11-06 20:40:46 77,ysios_receipt_ee6bed338a32f836a999133cd2e6d547,27388294,yriu1244_16043_001,2616,98.00,2017-10-19 22:27:46 76,ysios_receipt_ae53b142924c0604820537d61a9dd73e,27424976,yriu1244_16043_001,2616,648.00,2017-10-19 12:10:17 79,ysios_receipt_30ec130bcdf0e864629d12f8392d4b43,27385229,yriu1244_16043_001,2616,98.00,2017-10-21 07:46:01 78,ysios_receipt_e2b62024f1b0c3a2c3aae1e80f126eb6,27387306,yriu1244_16043_001,2616,25.00,2017-10-20 01:54:24 81,ysios_receipt_3e72a8e32c9fee546ab08d103606e6cb,27424976,yriu1244_16043_001,2616,30.00,2017-10-21 13:55:54 80,ysios_receipt_6ca291884fcfe3d1583b49a3611b4ccc,27424976,yriu1244_16043_001,2616,25.00,2017-10-21 13:55:51 [
[email protected]
~]$ wc -l ios_pay.txt 20027 ios_pay.txt [[email protected] ~]$ du -sh ios_pay.txt 1.9M ios_pay.txt

現在文字“ios_pay.txt”有20027行記錄,大小約2M。

copy命令語法
lottu=# \h copy
Command:     COPY
Description: copy data between a file and a table
Syntax:
COPY table [(column [, ...])] FROM {'file' | STDIN}
     [ [WITH] 
       [OIDS]
       [HEADER]
       [DELIMITER [ AS ] 'delimiter']
       [NULL [ AS ] 'null string']
       [ESCAPE [ AS ] 'escape' | 'OFF']
       [NEWLINE [ AS ] 'LF' | 'CR' | 'CRLF']
       [CSV [QUOTE [ AS ] 'quote'] 
            [FORCE NOT NULL column [, ...]]
       [FILL MISSING FIELDS]
     [ [LOG ERRORS INTO error_table] [KEEP] 
       SEGMENT REJECT LIMIT count [ROWS | PERCENT] ]


COPY {table [(column [, ...])] | (query)} TO {'file' | STDOUT}
      [ [WITH] 
        [OIDS]
        [HEADER]
        [DELIMITER [ AS ] 'delimiter']
        [NULL [ AS ] 'null string']
        [ESCAPE [ AS ] 'escape' | 'OFF']
        [CSV [QUOTE [ AS ] 'quote'] 
             [FORCE QUOTE column [, ...]] ]

資料載入使用:copy table…from語句
資料匯出使用:copy…to語句
常用引數
分隔符:[DELIMITER [ AS ] 'delimiter']
處理空列(含有空格符的是不行的):[NULL [ AS ] 'null string']
記錄錯誤資料,錯誤日誌表自動建立: [LOG ERRORS INTO error_table] [KEEP]
允許錯誤的行數或者百分比,大於指定值匯入失敗全部回滾:SEGMENT REJECT LIMIT count [ROWS | PERCENT] ]

資料匯入

對於copy命令,執行的使用者必須擁有superuser許可權

lottu=# \du lottu
                List of roles
 Role name |      Attributes      | Member of 
-----------+----------------------+-----------
 lottu     | Superuser, Create DB | 

執行命令:

copy tbl_pay_log_copy from '/home/gpadmin/ios_pay.txt' with delimiter ',' null '' ;
//將檔案匯入到tbl_pay_log_copy 表中,分隔符為‘,’

可以通過下面語句檢視匯入的資料是否出現傾斜的情況:

select gp_segment_id,count(*) from tbl_pay_log_copy group by 1;
資料解除安裝

Copy工具不僅可以把資料從檔案載入到資料庫的表中,也可以將資料從資料庫的表中解除安裝到作業系統的檔案中。如下:

命令:

copy tbl_pay_log_copy to '/home/gpadmin/tbl_pay_log_copy_output.txt' WITH DELIMITER AS ',';

也可以根據query進行解除安裝,這樣可以根據需求匯出自己需要的記錄或者列記錄。如下命令:

copy (select * from tbl_pay_log_copy where id = 73) to '/home/gpadmin/tbl_pay_log_copy_id_73.txt' WITH DELIMITER AS ',';

檢視匯出檔案

[[email protected] ~]$ ll tbl_pay_log_copy_output.txt tbl_pay_log_copy_id_73.txt
-rw-r--r--. 1 gpadmin gpadmin     109 Apr 18 22:52 tbl_pay_log_copy_id_73.txt
-rw-r--r--. 1 gpadmin gpadmin 1917463 Apr 18 22:50 tbl_pay_log_copy_output.txt

使用SELECT的COPY效率比直接使用表名COPY效率低很多,對於資料量稍大的表,可以考慮使用中間表結合COPY的方式來解除安裝資料

外部表及gpfdist

外部表提供了對Greenplum資料庫之外的來源中資料的訪問。可以用SELECT語句訪問它們,外部表通常被用於抽取、裝載、轉換(ELT)模式,這是一種抽取、轉換、裝載(ETL)模式的變種,這種模式可以利用Greenplum資料庫的快速並行資料裝載能力。這是COPY命令不具有的。
在這裡插入圖片描述

gpfdist原理:

gpfdist是一個使用HTTP協議的檔案伺服器程式,它以並行的方式向Greenplum資料庫的Segment供應外部資料檔案。一個gpfdist例項,每秒能供應200MB,並且很多gpfdist程序可以同時執行,每一個供應要被裝載的資料的一部分。
當使用者用INSERT INTO <table> SELECT * FROM <external_table>這樣的語句開始裝載時,INSERT語句會被Master解析並且分佈給主Segment。Segment連線到gpfdist伺服器並且並行檢索資料,解析並驗證資料,從分佈鍵資料計算一個雜湊值並且基於雜湊鍵把行傳送給它的目標Segment。每個gpfdist例項預設將接受最多64個來自Segment的連線。通過讓許多Segment和gpfdist伺服器參與到裝載處理中,可以以非常高的速率被裝載。

建立實驗環境

lottu=# create table tbl_pay_log_gpfdist(id int primary key,order_num varchar(100),accountid varchar(30),qn varchar(20),appid int,amount numeric(10,2),pay_time timestamp);

lottu=# \d tbl_pay_log_gpfdist
         Table "public.tbl_pay_log_gpfdist"
  Column   |            Type             | Modifiers 
-----------+-----------------------------+-----------
 id        | integer                     | not null
 order_num | character varying(100)      | 
 accountid | character varying(30)       | 
 qn        | character varying(20)       | 
 appid     | integer                     | 
 amount    | numeric(10,2)               | 
 pay_time  | timestamp without time zone | 
Indexes:
    "tbl_pay_log_gpfdist_pkey" PRIMARY KEY, btree (id), tablespace "tbs_lottu"
Distributed by: (id)
Tablespace: "tbs_lottu"

資料可使用copy小節列出的資料。

gpfdist資料載入

在看下gpfdist工具,gpfdist工具可以實驗並行載入,需要先啟動gpfdist程序及監聽埠,這個命令在Master和Segment節點的GPHOME/bin目錄下,如果配置了GP的環境變數,可以直接使用,如果在沒有安裝GP的伺服器上使用gpfdist工具,只需要將gpfdist命令的檔案拷貝到相應的伺服器上即可使用。

本實驗檔案在Master節點上;只需在Master啟動。
分為以下幾個步驟
1:啟動gpfdist程序及監聽埠
命令:

nohup gpfdist -d /home/gpadmin -p 1234 -l /home/gpadmin/gpfdist.log &
//啟動gpfdist程序,掃描路徑為/home/gpadmin/,監聽埠為1234

2:建立一張基於gpfdist工具的外部表

create external table med_pay_log_gpfdist
(id int,order_num varchar(100),accountid varchar(30),qn varchar(20),appid int,amount numeric(10,2),pay_time timestamp)
location('gpfdist://mdw:1234/ios_pay.txt')
format 'TEXT' (DELIMITER as ',' null as ''ESCAPE as 'OFF')
encoding 'utf8' LOG ERRORS INTO med_pay_log_gpfdist_err SEGMENT REJECT LIMIT 100;

建立外部表時,注意外部表的一些特性,如欄位不能指定not null,不能指定primary key等。

3:載入資料
命令:

insert into tbl_pay_log_gpfdist select * from med_pay_log_gpfdist;

4:載入完成之後需要停掉gpfdist程序

[[email protected] ~]$ ps -ef|grep gpfdist|grep -v "grep"
gpadmin  28777 20448  0 00:32 pts/1    00:00:00 gpfdist -d /home/gpadmin -p 1234 -l /home/gpadmin/gpfdist.log
[[email protected] ~]$ kill 28777

5:刪除外部表

lottu=# drop external table med_pay_log_gpfdist;

GP資料庫查詢資料,先掃描到的資料會直接返回,也就是多次查詢的結果可能是不一樣的。使用gpfdist工具載入是並行載入的,最先插入到資料庫的資料並不一定是從第一條資料開始的。

gpfdist資料解除安裝

使用可寫外部表解除安裝資料時,如果使用gpfdist工具,就可以實現並行解除安裝,而且資料不需要經過Master節點,直接由Segment節點寫入到外部檔案中,效率比較高,解除安裝大量資料時,使用這種方式會節省大量的時間。

解除安裝步驟和載入步驟類似,下面測試通過可寫外部表並且使用gpfdist工具來解除安裝資料到sdw1主機上。
1:在sdw1主機啟動gpfdist程序

nohup gpfdist -d /home/gpadmin -p 1234 -l /home/gpadmin/gpfdist.log &

2:建立可寫外部表

lottu=# create writable external table med_pay_log_gpfdist_unload (like tbl_pay_log_gpfdist) location ('gpfdist://192.168.1.202:1234/unload.txt') Format 'text';

3:解除安裝資料

lottu=# insert into med_pay_log_gpfdist_unload select * from tbl_pay_log_gpfdist;

4:停掉gpfdist程序
5:刪除外部表

gpload

gpload是一種資料裝載工具,它扮演著Greenplum外部表並行裝載特性的介面的角色。gpload使用定義在一個YAML格式的控制檔案中的規範來執行一次裝載。

它會執行下列操作:
1.呼叫gpfdist程序;
2.基於定義的源資料建立一個臨時的外部表定義;
3.執行INSERT、UPDATE或者MERGE操作將源資料載入資料庫中的目標表;
4.刪除臨時外部表;
5.清除gpfdist程序;

建立實驗環境
create table tbl_pay_log_gpload (like tbl_pay_log_gpfdist);
建立YAML格式控制檔案

使用gpload工具,需要編寫gpload工具的控制檔案,這個控制檔案是使用yuml語言編寫,如下是gpload工具的演示:

---
VERSION: 1.0.0.1
DATABASE: lottu
USER: lottu
HOST: mdw
PORT: 5432
GPLOAD:
  INPUT:
    - SOURCE:
        LOCAL_HOSTNAME:
          - sdw1  
        PORT: 1234
        FILE:
          - /home/gpadmin/unload.txt
    - COLUMNS:
          - id: int
          - order_num: varchar
          - accountid: varchar
          - qn: varchar
          - appid: int
          - amount: numeric
          - pay_time: timestamp
    - FORMAT: text
    - ERROR_LIMIT: 25
    - error_table: public.tbl_pay_log_gpload_err
  OUTPUT:
    - TABLE: public.tbl_pay_log_gpload
    - MODE: INSERT
  SQL:
    - BEFORE: "truncate table public.tbl_pay_log_gpload"
    - AFTER: "ANALYZE tbl_pay_log_gpload"

特別提醒:“-”後一定要有空格;“:”後也一定要有空格。

引數說明:
VERSION     自定義版本號(可選項)
DATABASE    需要連線的資料庫,如果沒有指定,根據$PGDATABASE變數確定
USER        執行操作的使用者。如果沒指定,根據$PGUSER變數確定
HOST        可選項。指定master節點的主機名(IP)。如果沒指定,根據變數$PGHOST確定。
PORT        可選項。指定master的埠,預設是5432或者$GPORT。
GPLOAD      必須項。load部分的開始。一個GPLOAD部分必須包含一個INPUT和一個OUTPUT。
INPUT       必須項。定義載入資料的格式和位置。gpload在當前主機上啟動一個或者多個gpfdist檔案分散式例項 。注意,gpload命令所在主機可網路訪問Greenplum中的每個節點(master&segment)。
SOURCE      必須項。INPUT部分的SOURCE塊其定義了source檔案所在位置。一個INPUT部分中可以有1個或者多個SOURCE塊定義。每個SOURCE塊定義對應了一個本機的gpfdist例項。每個SOURCE塊定義必須制定一個source檔案。
LOCAL_HOSTNAME    可選項。gpload工具執行所在的主機名或者IP地址。如果這臺主機有多個網絡卡,能同時使用每個網絡卡(每個網絡卡都有一個IP地址),通過設定LOCAL_HOSTNAME和PORT 實現多個gpfdist例項,可提升資料載入速度。預設情況,只使用主主機名或者IP地址。
PORT        可選項。gpfdist例項需要的埠。                    
FILE        必須項。檔案位置。可同時制定多個相同格式的檔案,入/home/gpadmin/script/*.txt。如果是gzip或bzip2檔案,會自動解壓(在環境變數中設定好gunzip、bunzip2的路徑)。
CLOUMNS     可選項。說明source檔案的格式,列名:資料型別。DELIMITER引數,指明source檔案中兩個資料之間的分隔符。如果沒有指定COLUMNS選項,意味著source檔案中的列的順序、列的數量、資料型別都和目標表一致。COLUMN的作用:SOURCE_TO_TARGET的mapping關係。
FORMAT      可選項。source檔案的型別,比如text、csv。預設text格式不說指定。
DELIMITER   可選項。一行資料中,各列的分隔符號。TEXT格式中預設tab作為分隔符;CSV中以都好","作為分隔符。
ERROR_LIMIT 可選項。允許的錯誤行數。載入資料時,錯誤資料將被忽略。如果沒有到達錯誤限制數量,所有正常行會載入到GP中,問題行會存放到err_table中。如果超過錯誤值,正常資料也不會載入。
ERROR_TABLE 可選項。前提是開啟了ERROR_LIMIT 。錯誤表將記錄錯誤行。如果錯誤表不存在,會自動建立。若存在,直接插入資料。
EXTERNAL    可選項。定義外部表。
OUTPUT      必須項。定義最終source檔案載入到的目標表。
TABLE       必須項。目標表。
MODE        可選項。有三種模式:insert,插入資料; update,當MATCH_COLUMNS引數值(相當於關聯列)等於載入資料時,更新UPDATE_COLUMS引數設定的列(相當於update的列)。 並且,必須設定UPDATE_CONDITION引數(相當於where過濾條件)。merge,  載入資料時,插入目標表中不存在的資料,更新目標中存在的資料。
MATCH_COLUMNS       在UPDATE或者MERGE模式下使用。相當於關聯列。這裡寫目標表的列名。
UPDATE_COLUMNS      在UPDATE或者MERGE模式下使用。更新的目標表列名。
UPDATE_CONDITION    可選項。目標表的列名,相當於where條件。用在update或者merge模式。
MAPPING      可選項。如果設定了MAPPING引數,那麼前面設定的COLUMNS引數會失效,因為MAPPING級別高於COLUMNS。關聯格式:target_column_name: source_column_name。where過濾格式:target_column_name: 'expression'
RELOAD       可選項。匯入時,是truncate之前目標表的資料,還是保留目標表資料。兩種模式,TRUNCATE 和REUSE_TABLES。
SQL          可選項。定義開始執行gpload和gpload結束執行的SQL語句。BEFORE,開始執行gpload執行的SQL,SQL需引號括起來;AFTER,gpload結束後執行的SQL,SQL需引號括起來。
載入資料

然後使用gpload工具,將資料載入到資料庫。

[[email protected] ~]$ gpload -f gpload.yml
2018-04-19 18:28:37|INFO|gpload session started 2018-04-19 18:28:37
Password: 
2018-04-19 18:28:40|INFO|started gpfdist -p 1234 -P 1235 -f "/home/gpadmin/unload.txt" -t 30
2018-04-19 18:28:42|INFO|running time: 5.38 seconds
2018-04-19 18:28:43|INFO|rows Inserted          = 22052
2018-04-19 18:28:43|INFO|rows Updated           = 0
2018-04-19 18:28:43|INFO|data formatting errors = 0
2018-04-19 18:28:43|INFO|gpload succeeded

資料裝載效能技巧

在裝載前刪除索引

若裝載一張新建立的表,最快的方式是先建立表,再裝載資料,然後再建立任何需要的索引。在已存在的資料上建立索引比不斷的遞增索引要快。若向一個已有的表新增大量資料,更快的方式可能是,先刪除索引,然後裝載資料,然後再重新建立索引。臨時的增加maintenance_work_mem伺服器引數可以提升CREATE INDEX名的速度,不過,這可能對於裝載資料本身沒有效能提升。應該考慮在沒有系統使用者在用時進行刪除並重新建立索引操作。

在裝載之後執行ANALYZE

在修改了表中的大部分資料之後,強烈建議執行ANALYZE操作。執行ANALYZE(或者VACUUM ANALYZE)以確保查詢規劃器擁有最新的統計資訊。如果沒有統計資訊或者統計資訊過時了,規劃器可能會根據過期的統計資訊或不存在的統計資訊選擇一個較差的查詢計劃,以至導致較差的效能。

在裝載出錯後執行VACUUM

如果執行的不是單條記錄錯誤隔離模式,裝載操作將在首次發生錯誤時終止。而目標表已經收到了錯誤發生前的記錄。這些記錄是無法被訪問的,但它們仍佔據磁碟空間。若這種情況發生在大的裝載操作上,會導致大量的磁碟空間浪費。執行VACUUM命令可以回收這些浪費的空間。

在裝載期間通過將gp_autostats_mode配置引數設定為NONE禁用自動統計資訊收集。set gp_autostats_mode = none;

使用gpfdist和gpload裝載資料的詳細指導請見《Greenplum資料庫參考指南》。