综述:greenplum数据加载主要包括insert、copy、外部表、gpload、web external table等五种方式。其中insert和copy是串行;外部表gpfdist和gpload工具是并行方式。
1.insert效率最差。
insert into t values(null,'szlsd'); 正确
insert into t values(‘’,'szlsd'); 错误
2.copy比insert效率好点。
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 [, ...]] ]
[IGNORE EXTERNAL PARTITIONS ]
常用参数
分隔符:[DELIMITER [ AS ] ‘delimiter’]
处理空列(含有空格符的是不行的):[NULL [ AS ] ‘null string’]
记录错误数据,错误日志表自动创建: [[LOG ERRORS [INTO error_table] [KEEP]
允许错误的行数,大于指定值导入失败全部回滚:SEGMENT REJECT LIMIT count [ROWS | PERCENT] ]
3.gpfdist
外部表,就是在数据库中只有表定义、没有数据,数据都存放在数据库之外的数据文件。greenplum可以对一个外部表执行正常的DML操作,当读取数据的时候,数据库从数据文件中加载数据。外部表支持在segment上并发地告诉从gpfdist导入数据,由于是从segment上导入数据,所以效率很高。
外部表需要指定gpfdist的IP和端口,还要有详细的目录地址,文件名支持通配符匹配。可以编写多个gpfdist地址,但是总数不能超过总的segment数量,否则会报错。
GPDB提供两种外部表:可读外部表用于数据装载、可写外部表用于数据卸载。外部表可基于文件、亦可基于WEB,这两种都能实现可读、可写。
CREATE [READABLE] EXTERNAL TABLE table_name
( column_name data_type [, ...] | LIKE other_table )
LOCATION ('file://seghost[:port]/path/file' [, ...])
| ('gpfdist://filehost[:port]/file_pattern[#transform]'
| ('gpfdists://filehost[:port]/file_pattern[#transform]'
[, ...])
| ('gphdfs://hdfs_host[:port]/path/file')
FORMAT 'TEXT'
[( [HEADER]
[DELIMITER [AS] 'delimiter' | 'OFF']
[NULL [AS] 'null string']
[ESCAPE [AS] 'escape' | 'OFF']
[NEWLINE [ AS ] 'LF' | 'CR' | 'CRLF']
[FILL MISSING FIELDS] )]
| 'CSV'
[( [HEADER]
[QUOTE [AS] 'quote']
[DELIMITER [AS] 'delimiter']
[NULL [AS] 'null string']
[FORCE NOT NULL column [, ...]]
[ESCAPE [AS] 'escape']
[NEWLINE [ AS ] 'LF' | 'CR' | 'CRLF']
[FILL MISSING FIELDS] )]
| 'AVRO'
| 'PARQUET'
| 'CUSTOM' (Formatter=
[ ENCODING 'encoding' ]
[ [LOG ERRORS [INTO error_table]] SEGMENT REJECT LIMIT count
[ROWS | PERCENT] ]
CREATE [READABLE] EXTERNAL WEB TABLE table_name
( column_name data_type [, ...] | LIKE other_table )
LOCATION ('http://webhost[:port]/path/file' [, ...])
| EXECUTE 'command' [ON ALL
| MASTER
| number_of_segments
| HOST ['segment_hostname']
| SEGMENT segment_id ]
FORMAT 'TEXT'
[( [HEADER]
[DELIMITER [AS] 'delimiter' | 'OFF']
[NULL [AS] 'null string']
[ESCAPE [AS] 'escape' | 'OFF']
[NEWLINE [ AS ] 'LF' | 'CR' | 'CRLF']
[FILL MISSING FIELDS] )]
| 'CSV'
[( [HEADER]
[QUOTE [AS] 'quote']
[DELIMITER [AS] 'delimiter']
[NULL [AS] 'null string']
[FORCE NOT NULL column [, ...]]
[ESCAPE [AS] 'escape']
[NEWLINE [ AS ] 'LF' | 'CR' | 'CRLF']
[FILL MISSING FIELDS] )]
| 'CUSTOM' (Formatter=
[ ENCODING 'encoding' ]
[ [LOG ERRORS [INTO error_table]] SEGMENT REJECT LIMIT count
[ROWS | PERCENT] ]
CREATE WRITABLE EXTERNAL TABLE table_name
( column_name data_type [, ...] | LIKE other_table )
LOCATION('gpfdist://outputhost[:port]/filename[#transform]'
| ('gpfdists://outputhost[:port]/file_pattern[#transform]'
[, ...])
| ('gphdfs://hdfs_host[:port]/path')
FORMAT 'TEXT'
[( [DELIMITER [AS] 'delimiter']
[NULL [AS] 'null string']
[ESCAPE [AS] 'escape' | 'OFF'] )]
| 'CSV'
[([QUOTE [AS] 'quote']
[DELIMITER [AS] 'delimiter']
[NULL [AS] 'null string']
[FORCE QUOTE column [, ...]] ]
[ESCAPE [AS] 'escape'] )]
| 'AVRO'
| 'PARQUET'
| 'CUSTOM' (Formatter=
[ ENCODING 'write_encoding' ]
[ DISTRIBUTED BY (column, [ ... ] ) | DISTRIBUTED RANDOMLY ]
CREATE WRITABLE EXTERNAL WEB TABLE table_name
( column_name data_type [, ...] | LIKE other_table )
EXECUTE 'command' [ON ALL]
FORMAT 'TEXT'
[( [DELIMITER [AS] 'delimiter']
[NULL [AS] 'null string']
[ESCAPE [AS] 'escape' | 'OFF'] )]
| 'CSV'
[([QUOTE [AS] 'quote']
[DELIMITER [AS] 'delimiter']
[NULL [AS] 'null string']
[FORCE QUOTE column [, ...]] ]
[ESCAPE [AS] 'escape'] )]
| 'CUSTOM' (Formatter=
[ ENCODING 'write_encoding' ]
[ DISTRIBUTED BY (column, [ ... ] ) | DISTRIBUTED RANDOMLY ]
参数说明:
location 文件所在位置,可以直接是本地路径、gpfdist地址、gpfdists地址、gphdfs地址。
format 文本类型
delimiter 分隔符
encoding 编码
log error into 错误数据表,记录错误数据,会自动创建。一般都是tablename_err格式,例如t1_err。
segment reject limit 错误数据的条数/百分比(rows/percent),超过设置值会报错。最小值是2。用来确保数据的完整性。
4.gpload
gpload是GP使用可读外部表和GP并行文件服务gpfdist装载数据的一个命令包装。
5.gpfdist性能优化
1,737 total views, 1 views today
在 《Greenplum数据加载方式(2) – 外部表(gpfdist)》 和 《Greenplum数据加载方式(3) – gpload》 两篇文章中都使用到了gpfdist。本篇文章将详细介绍gpfdist的工作原理;Greenplum主要适用于大数据场景,数量都是TB级别,那么利用gpfdist加载数据必须要高效,因此gpfdist的性能优化也很重要。
一、工作原理
<1>启动gpfdist,并在Master上建表。表建好后并没有任何数据流动,只是定义好了外部表的原始数据信息。
<2>将外部表插入到一张Greenplum的物理表中,开始导入数据。
<3>Segment根据建表时定义的gpfdist url个数,启动相同的并发到gpfdist获取数据,其中每个Segment节点都会连接到gpfdist上获取数据。
<4>gpfdist收到Segment的连接并要接收数据时,开始读取文件,顺序读取文件,然后将文件拆分成多个块,随机抛给Segment。
<5>由于gpfdist并不知道数据库中有多少个Segment,数据是按照哪个分布键拆分的,因此数据是随机发送到每个Segment上的,数据到达Segment的时间基本上是随机的,所以外部表可以看成是一张随机分布的表,将数据插入到物理表的时候,需要进行一次重新分布。
<6>为了提高性能,数据读取于与重分布是同时进行的,当数据重分布完毕后,整个数据导入流程结束。
二、gpfdist最主要的功能
<1>负载均衡:每个Segment分配到的数据都是随机的,所以每个节点的负载都非常均衡。
<2>并发读取,性能高:每台Segment都同时通过网卡到文件服务器获取数据,并发读取,从而获取了比较高的性能。相对于copy命令,数据要通过Master流入,使用外部表就消除了Master这个单点问题。
三、如何提高gpfdist性能
Greenplum数据导入,容易出瓶颈的2个地方。
<1>文件服务器
因为所有Segment都连接到文件服务器上获取数据,所以如果文件服务器是单机的,那么文件服务器很容易在磁盘IO和网卡上出现性能瓶颈。
<2>Segment节点
Segment节点比文件系统要多不少,Segment一般不会出现磁盘IO和网卡性能问题。当Segment出现瓶颈时,数据导入引起的瓶颈可能性极小,更多的是整个数据库的性能都出现了瓶颈。
四、如何提高文件服务器性能
<1>IO出现瓶颈。考虑使用磁盘阵列,也可以采用分布式文件系统来提高整体性能,如MooseFS。
<2>网卡出现瓶颈。第一种方法:换成万兆网卡,这种方式成本很高,因为还需要万兆交换机等。第二种方法:通过多网卡机制来解决网络带宽瓶颈。
例如:
1 2 3 4 5 6 7 |
CREATE EXTERNAL TABLE table_name (column_name date_type [,...] like other table) LOCATION ('gpfist://filehostip1[:port1]/file_pattern1', 'gpfist://filehostip2[:port2]/file_pattern2', 'gpfist://filehostip3[:port3]/file_pattern3', 'gpfist://filehostip4[:port4]/file_pattern4' ) |
我们可以只启动一个gpfdist,通过不同ip连接到gpfdist上,这样文件的gpfdist只有一个,不能实现IO并发,但是网卡可以使用多张,从而消除网卡瓶颈。