Greenplum通过外表,使得segment连接到gpfdist服务,获取数据。
gpfdist随机分发数据到各个segment中。
gpfdist线性处理,一次处理一个文本。根据服务器情况,可启动多个gpfdist服务。
在ETL服务器上启动gpfdist服务
创建脚本文件gpfdistServer.sh,gpfdist后台启动
#!/bin/bash
# 指定了端口,指定了文件主目录(可不指定)
nohup /opt/greenplum/greenplum-db/bin/gpfdist -p 8080 -d /edw/data > /dev/null 2>&1 &
用户需要有创建外表的权限,只读外表/可写外表
--cascade 把关联的表/视图也删掉
drop external table ext.test cascade;
create external table ext.test(
num integer,
name varchar(32),
income decimal(18,2)
start_dt date,
create_dt timestamp
) location('gpfdist://192.168.1.110:8080/tmp/ITEM.csv')
FORMAT 'CSV' (DELIMITER '|')
location 指定了gpfdist服务和文件的位置
gpfdist启动指定了路径为/edw/data,外表设置的文件路径为/tmp/ITEM.csv
文件在ETL服务器的绝对路径为:/edw/data/tmp/ITEM.csv
注意:gpfdist所在服务器要能被gp集群访问,此处ELT服务器和gp互相可访问。
-- 外表结构也可以用like
create external table ext.test(like ext.test1
) location('gpfdist://192.168.1.110:8080/tmp/ITEM.csv')
FORMAT 'CSV' (DELIMITER '|')
文件可以是压缩的,可以是未压缩的
drop table if exists ob.test;
create table ob.test(
num integer,
name varchar(32),
income decimal(18,2)
start_dt date,
create_dt timestamp
) with(OIDS=false) DISTRIBUTED BY(num );
insert into ob.test select * from ext.test;
explain insert into ob.test select * from ext.test;
普通文件
1.当删除ETL的普通文件/edw/data/tmp/ITEM.csv,查询外表会ext.test报错
2.当删除外表ext.test时,ETL的普通文件仍然在服务器中
3.外表创建成功后,当删除ETL的普通文件时,此时查询外表报错
4.当gpfdist服务停止时,此时查询只读外表报错
5.普通文件尽量是解压后的文件
管道文件
1.创建外表方式和普通文件的方式一样
2.创建外表,此时外表进程卡住的,此时相当于生成者生产了数据,需要消费者消费才能知道是什么数据。如当插入到内部表时,数据被消费掉。
3.管道文件不占I/O,减少磁盘开销
COMMENT ON TABLE ext.test IS '测试表';
COMMENT ON COLUMN ext.test.num IS '编号';
加载不同的gpfdist服务器中的文件,分隔符为 | ,NULL值为空字符串。
LOG ERRORS 只读外表可设置,可写外表不能设置。
-- 只读外表
CREATE EXTERNAL TABLE ext.test(
num integer,
name varchar(32),
income decimal(18,2)
start_dt date,
create_dt timestamp
)
LOCATION ('gpfdist://192.168.1.110:8080/tmp/ITEM.csv',
'gpfdist://192.168.1.111:8080/tmp/ITEM.csv')
FORMAT 'CSV' (DELIMITER '|' NULL '')
LOG ERRORS SEGMENT REJECT LIMIT 100;
内置的函数fixedwidth_in (加载用),fixedwidth_out(导出用)
CUSTOM 设置各个字段对应数据的长度
CREATE EXTERNAL TABLE ext.test(
num integer,
name varchar(32),
income decimal(18,2)
start_dt date,
create_dt timestamp
)
LOCATION ('gpfdist://192.168.1.110:8080/tmp/ITEM2.dat')
FORMAT 'CUSTOM' (formatter=fixedwidth_in,
num='12', name='32', income='20',start_dt='8',create_dt='19');
LOG ERRORS SEGMENT REJECT LIMIT 100;
CREATE EXTERNAL TABLE ext.test(
num integer,
name varchar(32),
income decimal(18,2)
start_dt date,
create_dt timestamp
)
LOCATION ('gpfdist://192.168.1.110:8080/tmp/ITEM2.dat'
FORMAT 'CUSTOM' (formatter=fixedwidth_in,
num='12', name='32', income='20',start_dt='8',create_dt='19',line_delim='');
LOG ERRORS SEGMENT REJECT LIMIT 100;
配置文件gpload.yaml
VERSION: 1.0.0.1
DATABASE: gpdb
USER: testuser
PASSWORD: 123456
HOST: 192.168.0.110
PORT: 5432
GPLOAD:
INPUT:
- SOURCE:
FILE:
- /data/import/test.txt
- COLUMNS: #txt中每列的顺序
- id: text
- name: text
- FORMAT: text
- DELIMITER: ','
- ERROR_LIMIT: 25
- LOG_ERRORS: true
OUTPUT:
- TABLE: ext.load_test
- MODE: INSERT
PRELOAD:
- REUSE_TABLES: true
启动gpload
gpload -f gpload.yaml -l ./gpload.log &
delimiter 指定文件字段之间的分隔符
header 声明文件存在表头,默认false
format 取值text/csv,设置文件类型
quote 指定引号作为字段引号
encoding 指定文件的编码格式
null 指定对null值处理 ,一般null ‘’
escape 指定文件转义字符E’\t’
ESCAPE as ‘OFF’ 关闭转义,默认打开
Greenplum数据库要求数据行由LF字符(换行,0x0A)、CR(回车,0x0D)或CR后跟LF(CR+LF,0x0D0x0A)分隔。LF是UNIX或类UNIX操作系统上的标准换行表示。Windows或Mac OS X等操作系统使用CR或CR+LF。Greenplum数据库支持所有这些换行符表示形式作为行分隔符。有关详细信息,请参见导入和导出固定宽度数据。
默认的列或字段分隔符是文本文件的水平TAB字符(0x09)和CSV文件的逗号字符(0x2C)。定义数据格式时,可以使用COPY、CREATE EXTERNAL TABLE或gpload的delimiter子句声明单字符分隔符。分隔符必须出现在任意两个数据值字段之间。不要在行的开头或结尾放置分隔符。例如,如果管道字符(|)是分隔符:
以下命令显示了管道字符作为列分隔符的使用:
DELIMITER ‘|’
NULL表示列或字段中的未知数据。在数据文件中,可以指定一个字符串来表示空值。在TEXT模式下,默认字符串为\N(反斜杠-N),或者在CSV模式下为空值,不带引号。定义数据格式时,还可以使用COPY、CREATE EXTERNAL TABLE或gpload的NULL子句声明不同的字符串。例如,如果不想区分NULL和空字符串,可以使用空字符串。使用Greenplum数据库加载工具时,与指定的空字符串匹配的任何数据项都被视为空值。
有两个保留字符对Greenplum数据库具有特殊意义:
指定的分隔符分隔数据文件中的列或字段。
换行符指定数据文件中的新行。
如果数据包含这些字符中的任何一个,则必须对该字符进行转义,以便Greenplum将其视为数据,而不是字段分隔符或新行。默认情况下,对于文本格式的文件,转义字符是\(反斜杠),对于csv格式的文件则是双引号(“)。
默认情况下,转义字符是文本格式文件的\(反斜杠)。您可以在COPY、CREATE EXTERNAL TABLE或gpload的escape子句中声明不同的转义字符。如果转义字符出现在数据中,请使用它来转义自身。
例如,假设您有一个包含三列的表,并且希望加载以下三个字段:
反斜杠=
垂直条=|
感叹号=!
指定的分隔符是|(管道字符),指定的转义字符是\(反斜杠)。数据文件中的格式化行如下所示:
backslash = \ | vertical bar = | | exclamation point = !
请注意,作为数据一部分的反斜杠字符是如何用另一个反斜杠符转义的,作为数据的一部分的管道字符是如何使用反斜杠符号转义的。
可以使用转义字符转义八进制和十六进制序列。转义值在加载到Greenplum数据库时转换为等效字符。例如,要加载与号字符(&),请使用转义字符转义其等效的十六进制(\0x26)或八进制(\046)表示。
您可以使用COPY、CREATE EXTERNAL TABLE或gpload的ESCAPE子句停用文本格式文件中的转义,如下所示
ESCAPE ‘OFF’
这对于包含许多反斜杠字符的输入数据非常有用,例如web日志数据。
默认情况下,对于CSV格式的文件,转义字符为“(双引号)。如果要使用不同的转义字符,请使用COPY、CREATE EXTERNAL TABLE或gpload的escape子句声明不同的转码字符。如果选定的转义符出现在数据中,则可以使用它来转义。
例如,假设您有一个包含三列的表,并且希望加载以下三个字段:
免费前往A、B
5.89
特价“1.79”
指定的分隔符字符为(逗号),指定的转义字符为“(双引号)。数据文件中的格式化行如下所示:
"Free trip to A,B","5.89","Special rate ""1.79"""
数据中包含逗号字符的数据值用双引号括起来。作为数据一部分的双引号用双引号转义,即使字段值用双引号括起来。
将整个字段嵌入一组双引号中可以确保保留前导和尾随空格字符:
"Free trip to A,B ","5.89 ","Special rate ""1.79"" "
在CSV模式下,所有字符都是有意义的。由空格或除DELIMITER之外的任何字符包围的带引号的值包括这些字符。如果从将CSV行填充为固定宽度的系统导入数据,这可能会导致错误。在这种情况下,在将数据导入Greenplum数据库之前,对CSV文件进行预处理以删除尾部空白。
字符编码系统由一种代码组成,该代码将字符集中的每个字符与其他字符(如数字序列或八位字节)配对,以便于数据传输和存储。Greenplum数据库支持多种字符集,包括ISO 8859系列等单字节字符集和EUC(扩展UNIX代码)、UTF-8和Mule内部代码等多字节字符集。服务器端字符集是在数据库初始化期间定义的,UTF-8是默认值,可以更改。客户端可以透明地使用所有受支持的字符集,但不支持在服务器中使用少数字符集作为服务器端编码。当将数据加载或插入Greenplum数据库时,Greenplus会将数据从指定的客户端编码透明地转换为服务器编码。当将数据发送回客户端时,Greenplum将数据从服务器字符编码转换为指定的客户端编码。
数据文件必须采用Greenplum数据库识别的字符编码。有关支持的字符集,请参阅《Greenplum数据库参考指南》。包含无效或不受支持的编码序列的数据文件在加载到Greenplum数据库时会遇到错误。
注意:对于在Microsoft Windows操作系统上生成的数据文件,在加载到Greenplum数据库之前,运行dos2unix系统命令以删除所有仅限Windows的字符。
注意:如果更改现有gpload控制文件中的ENCODING值,则必须手动删除使用先前ENCODING配置创建的任何外部表。如果REUSE_tables设置为true,gpload不会删除并重新创建外部表以使用新的ENCODING。
Unloading Data Using a Writable External Table
可写外部表只允许INSERT操作。必须授予表的INSERT权限,才能访问非表所有者或超级用户的用户。例如:
GRANT INSERT ON writable_ext_table TO admin;
要使用可写外部表卸载数据,请从源表中选择数据并将其插入可写外部表格。结果行输出到可写外部表。例如:
INSERT INTO writable_ext_table SELECT * FROM regular_table;
DETAIL: Last error was:extra data after last expected column
CONTEXT: External table xxx ,line N/A of gpfdist://xxxxxxx:"20220101, 10000001ABC, 2222, -.000, .00 "
描述:1.txt文件内容如下,文件utf8编码格式
20220101, 10000001ABC, 2222, -.000, .00
外表创建
drop external table if exists tmp.test restrict;
create external table tmp.test(like sddl.test)
location('gpfdist://etlhost:8080/data/import/test.txt')
FORMAT 'TEXT' (delimiter ',' null '' escape 'off')
ENCODING 'GB18030'
LOG ERRORS SEGMENT REJECT LIMIT 10;
解决方法:
检查字段数量、长度、文件的内容
创建外表完成后,并不能说明外表是正确的。
当查询外表时候,若外表有问题则默认将错误信息记录。
# 查询外表,若有问题则查询日志表
select * from tmp.test;
# 查询日志表,若有记录说明外表有问题
select * from gp_read_error_log('tmp.test') where cmdtime='2022-01-01 00:00:00';
# errmsg记录错误信息
# rawdata记录错误数据
gpfdist加载时候,经常遇到上述问题。
排查文件内容和表结构字段的数量、顺序及类型是否一致
按分隔符方式导出文件,注意转义符问题,如文件存在\线,加载失败。
delimiter E’\x0f’ NULL as ’ ’ ESCAPE as ‘OFF’ FILL MISSING FIELDS
ESCAPE as 'OFF’关闭转义
数据中有双引号
sed命令替换掉即可:# sed -i ‘s/"//g’ file
有效的方式,将字段分隔符设置不可见字符。
加载后查询提示0x00问题,postgresql无法存储0x00。
数据库UTF8,导出文件us-ascii。通过gpfdist加载按分隔符encoding指定ISO-8859-1加载之前通过sed替换掉文件的0x00为空。
# perl
system("sed -i 's/\\\\x00//g' $filename");
#shell
sed -i "s/\x00//g" $filename