标签:.sh 标准 ace segment 串行化 后台运行 substr more 完数
一、基本操作insert into products (name, price, product_no) values (‘Cheese‘, 9.99, 1);(2)仅指定列值
insert into products values (1, ‘Cheese‘, 9.99);(3)使用SELECT语句
insert into products select * from tmp_products where price < 100; insert into products (name, price, product_no) select * from tmp_products where price < 100;如果列有缺省值,可以在插入语句中省略该列名而使用缺省值。
insert into products (name, product_no) select name, product_no from tmp_products where price < 100;(4)显式一次插入多行
db1=# create table t (a int); CREATE TABLE db1=# insert into t values (1),(2),(3); INSERT 0 3 db1=# select * from t; a --- 1 2 3 (3 rows)如果需要快速插入大量数据,最好使用后面介绍的外部表或COPY命令,这些数据装载机制比INSERT更有效。
db1=# -- 整理pg_class系统表 db1=# vacuum pg_class; VACUUM db1=# -- 整理并分析pg_class系统表 db1=# vacuum analyze pg_class; VACUUM db1=# -- 整理并分析pg_class系统表的指定列 db1=# vacuum analyze pg_class (relname,relam,relpages,reltuples,relkind,relnatts,relacl,reloptions); VACUUM(2)配置空余空间映射
db1=# vacuum full pg_class; NOTICE: ‘VACUUM FULL‘ is not safe for large tables and has been known to yield unpredictable runtimes. HINT: Use ‘VACUUM‘ instead. VACUUMfree space map的大小由以下服务器配置参数所控制:
[gpadmin@hdp3 ~]$ hawq config -s max_fsm_pages GUC : max_fsm_pages Value : 200000max_fsm_relations(整数)设置free space map跟踪的最大表数。每个表槽位占用7字节左右的共享内存。缺省值为1000。设置该参数后需要重启HAWQ使其生效。
[gpadmin@hdp3 ~]$ hawq config -s max_fsm_relations GUC : max_fsm_relations Value : 10003. 其它操作
[gpadmin@hdp3 ~]$ hawq config -s gp_external_max_segs GUC : gp_external_max_segs Value : 64用户可能需要设置虚拟段的数量,例如一些用于处理外部表数据文件,一些执行其它的数据库处理。hawq_rm_nvseg_perquery_perseg_limit和hawq_rm_nvseg_perquery_limit参数控制并行虚拟段的数量,它们限制集群中一个gpfdist外部表上执行查询时使用的最大虚拟段数。
[gpadmin@hdp4 ~]$ gpfdist &
[gpadmin@hdp4 ~]$ gpfdist -d /home/gpadmin/load_data/ -p 8081 -l /home/gpadmin/log &
[gpadmin@hdp4 ~]$ gpfdist -d /home/gpadmin/load_data1/ -p 8081 -l /home/gpadmin/log1 & [gpadmin@hdp4 ~]$ gpfdist -d /home/gpadmin/load_data2/ -p 8082 -l /home/gpadmin/log2 &
yum install apr yum install libyamlHAWQ没有提供停止gpfdist的特殊命令,直接使用kill停止gpfdist进程。
[gpadmin@hdp4 ~]$ ps -ef |grep gpfdist |grep -v grep | awk ‘{print $2}‘|xargs kill -9
[gpadmin@hdp3 ~]$ wget http://gpfdist_hostname:port/filename
(2)创建gpfdist外部表
为了创建一个gpfdist外部表,需要指定输入文件的格式和外部数据源的位置。使用以下协议之一访问外部表数据源。一条CREATE EXTERNAL TABLE语句中使用的协议必须唯一,不能混用多个协议。[gpadmin@hdp4 ~]$ gpfdist -p 8081 -d /home/gpadmin/staging -l /home/gpadmin/log &使用gpfdist协议创建只读外部表example1,文件以管道符(|)作为列分隔符。
db1=# create external table example1 db1=# ( name text, date date, amount float4, category text, desc1 text ) db1=# location (‘gpfdist://hdp4:8081/*‘) db1=# format ‘text‘ (delimiter ‘|‘); CREATE EXTERNAL TABLE准备文本文件数据。
[gpadmin@hdp4 unload_data1]$ cd /home/gpadmin/staging [gpadmin@hdp4 staging]$ more a.txt aaa|2017-01-01|100.1|aaa|aaa bbb|2017-01-02|100.2|bbb|bbb [gpadmin@hdp4 staging]$ more b.txt aaa|2017-03-01|200.1|aaa|aaa bbb|2017-03-02|200.2|bbb|bbb查询外部表。
db1=# select * from example1; name | date | amount | category | desc1 ------+------------+--------+----------+------- aaa | 2017-01-01 | 100.1 | aaa | aaa bbb | 2017-01-02 | 100.2 | bbb | bbb aaa | 2017-03-01 | 200.1 | aaa | aaa bbb | 2017-03-02 | 200.2 | bbb | bbb (4 rows)
例2:多gpfdist实例外部表
在hdp3和hdp4上分别启动一个gpfdist实例。[gpadmin@hdp3 ~]$ gpfdist -p 8081 -d /home/gpadmin/staging -l /home/gpadmin/log & [gpadmin@hdp4 ~]$ gpfdist -p 8081 -d /home/gpadmin/staging -l /home/gpadmin/log &使用gpfdist协议创建只读外部表example2,文件以管道符(|)作为列分隔符,‘ ‘作为NULL。
db1=# create external table example2 db1-# ( name text, date date, amount float4, category text, desc1 text ) db1-# location (‘gpfdist://hdp3:8081/*.txt‘, ‘gpfdist://hdp4:8081/*.txt‘) db1-# format ‘text‘ ( delimiter ‘|‘ null ‘ ‘) ; CREATE EXTERNAL TABLE查询外部表,因为gpfdist://hdp3:8081/*.txt不存在而报错。
db1=# select * from example2; ERROR: http response code 404 from gpfdist (gpfdist://hdp3:8081/*.txt): HTTP/1.0 404 file not found (url.c:306) (seg0 hdp4:40000 pid=53784) (dispatcher.c:1801) db1=#将外部文件复制到hdp3的相关目录下。
[gpadmin@hdp4 staging]$ scp *.txt hdp3://home/gpadmin/staging/再次查询外部表,可以正确读取全部外部文件数据。
db1=# select * from example2; name | date | amount | category | desc1 ------+------------+--------+----------+------- aaa | 2017-01-01 | 100.1 | aaa | aaa bbb | 2017-01-02 | 100.2 | bbb | bbb aaa | 2017-03-01 | 200.1 | aaa | aaa bbb | 2017-03-02 | 200.2 | bbb | bbb aaa | 2017-01-01 | 100.1 | aaa | aaa bbb | 2017-01-02 | 100.2 | bbb | bbb aaa | 2017-03-01 | 200.1 | aaa | aaa bbb | 2017-03-02 | 200.2 | bbb | bbb (8 rows)
例3:带有错误日志的单gpfdist实例外部表
缺省在访问外部表时只要遇到一行格式错误的数据,就会立即返回错误,并导致查询失败。下面的语句设置了SEGMENT REJECT LIMIT的值,只有当一个segment上的错误数大于等于5时,整个外部表操作才会失败,并且不处理任何行。而当错误数小于5时,会将被拒绝的行写入一个错误表errs,其它数据行还可以正常返回。db1=# create external table example3 db1-# ( name text, date date, amount float4, category text, desc1 text ) db1-# location (‘gpfdist://hdp3:8081/*.txt‘, ‘gpfdist://hdp4:8081/*.txt‘) db1-# format ‘text‘ ( delimiter ‘|‘ null ‘ ‘) db1-# log errors into errs segment reject limit 5; NOTICE: Error table "errs" does not exist. Auto generating an error table with the same name CREATE EXTERNAL TABLE db1=# \d errs Append-Only Table "public.errs" Column | Type | Modifiers ----------+--------------------------+----------- cmdtime | timestamp with time zone | relname | text | filename | text | linenum | integer | bytenum | integer | errmsg | text | rawdata | text | rawbytes | bytea | Compression Type: None Compression Level: 0 Block Size: 32768 Checksum: f Distributed randomly db1=#准备一条格式错误的数据。
[gpadmin@hdp4 staging]$ more a.txt aaa|2017-01-01|100.1|aaa|aaa bbb|2017-01-02|100.2|bbb|bbb bbb,2017-01-02,100.2,bbb,bbb查询外部表,返回8条数据,错误数据进入了errs表。
db1=# select * from example3; NOTICE: Found 1 data formatting errors (1 or more input rows). Rejected related input data. name | date | amount | category | desc1 ------+------------+--------+----------+------- aaa | 2017-01-01 | 100.1 | aaa | aaa bbb | 2017-01-02 | 100.2 | bbb | bbb aaa | 2017-03-01 | 200.1 | aaa | aaa bbb | 2017-03-02 | 200.2 | bbb | bbb aaa | 2017-01-01 | 100.1 | aaa | aaa bbb | 2017-01-02 | 100.2 | bbb | bbb aaa | 2017-03-01 | 200.1 | aaa | aaa bbb | 2017-03-02 | 200.2 | bbb | bbb (8 rows) db1=# \x Expanded display is on. db1=# select * from errs; -[ RECORD 1 ]----------------------------------------------------- cmdtime | 2017-04-05 15:23:19.579421+08 relname | example3 filename | gpfdist://hdp4:8081/*.txt [/home/gpadmin/staging/a.txt] linenum | 3 bytenum | errmsg | missing data for column "date" rawdata | bbb,2017-01-02,100.2,bbb,bbb rawbytes | db1=#准备5条错误数据。
[gpadmin@hdp4 staging]$ more a.txt aaa|2017-01-01|100.1|aaa|aaa bbb|2017-01-02|100.2|bbb|bbb b1,2017-01-02,100.2,bbb,bbb b2,2017-01-02,100.2,bbb,bbb b3,2017-01-02,100.2,bbb,bbb b4,2017-01-02,100.2,bbb,bbb b5,2017-01-02,100.2,bbb,bbb再次查询外部表,因为达到了错误上限,整条语句失败,没有数据被返回。
db1=# select * from example3; ERROR: Segment reject limit reached. Aborting operation. Last error was: missing data for column "date" (seg16 hdp3:40000 pid=350431) DETAIL: External table example3, line 7 of gpfdist://hdp4:8081/*.txt: "b5,2017-01-02,100.2,bbb,bbb" db1=#
例4:gpfdist可写外部表
建立可写外部表,并插入一条数据。db1=# create writable external table example4 (name text, date date, amount float4, category text, desc1 text) db1-# location (‘gpfdist://hdp4:8081/sales.out‘, ‘gpfdist://hdp3:8081/sales.out‘) db1-# format ‘text‘ ( delimiter ‘|‘ null ‘ ‘) db1-# distributed by (name); CREATE EXTERNAL TABLE db1=# insert into example4 values (‘aaa‘,‘2017-01-01‘,100.1,‘aaa‘,‘aaa‘); INSERT 0 1结果只在hdp4上建立了文件/home/gpadmin/staging/sales.out,而hdp3并没有建立输出文件。
[gpadmin@hdp4 staging]$ more sales.out aaa|2017-01-01|100.1|aaa|aaa再次建立可写外部表,将gpfdist位置调换,把hdp3放前面,并插入一条数据。
db1=# drop external table example4; DROP EXTERNAL TABLE db1=# create writable external table example4 (name text, date date, amount float4, category text, desc1 text) db1-# location (‘gpfdist://hdp3:8081/sales.out‘, ‘gpfdist://hdp4:8081/sales.out‘) db1-# format ‘text‘ ( delimiter ‘|‘ null ‘ ‘) db1-# distributed by (name); CREATE EXTERNAL TABLE db1=# insert into example4 values (‘aaa‘,‘2017-01-01‘,100.1,‘aaa‘,‘aaa‘); INSERT 0 1这次只在hdp3上建立了文件/home/gpadmin/staging/sales.out。
[gpadmin@hdp3 staging]$ more sales.out aaa|2017-01-01|100.1|aaa|aaa在LOCATION子句中指定同一主机上的多个gpfdist实例,结果也是一样的。可见,在可写外部表上执行INSERT操作时,只在第一个gpfdist实例的位置上生成本地文件数据。
(1)基于命令的web外部表
用一个shell命令或脚本的输出定义基于命令的web表数据。在CREATE EXTERNAL WEB TABLE语句的EXECUTE子句指定需要执行的命令。外部表中的数据是命令运行时的数据。EXECUTE子句运行特定master或虚拟段上的shell命令或脚本。脚本必须是gpadmin用户可执行的,并且位于所有master和segment主机的相同位置上,虚拟段并行运行命令。CREATE EXTERNAL WEB TABLE output (output text) EXECUTE ‘PATH=/home/gpadmin/programs; export PATH; myprogram.sh‘ ON MASTER FORMAT ‘TEXT‘;下面的命令定义一个web表,在五个虚拟段上运行一个名为get_log_data.sh脚本文件。
CREATE EXTERNAL WEB TABLE log_output (linenum int, message text) EXECUTE ‘/home/gpadmin/get_log_data.sh‘ ON 5 FORMAT ‘TEXT‘ (DELIMITER ‘|‘);资源管理器在运行时选取虚拟段。
(2)基于URL的Web外部表
基于URL的web表使用HTTP协议从web服务器访问数据,web表数据是动态的。在LOCATION子句中使用http://指定文件在web服务器上的位置。web数据文件必须在所有segment主机能够访问的web服务器上。URL的数量对应访问该web表时并行的最少虚拟段数量。下面的例子定义了一个从多个URL获取数据的web表。CREATE EXTERNAL WEB TABLE ext_expenses ( name text, date date, amount float4, category text, description text) LOCATION (‘http://hdp1/sales/file.csv‘, ‘http://hdp1/exec/file.csv‘, ‘http://hdp1/finance/file.csv‘, ‘http://hdp1/ops/file.csv‘, ‘http://hdp1/marketing/file.csv‘, ‘http://hdp1/eng/file.csv‘ ) FORMAT ‘CSV‘;
(3)基于Web的外部表示例
例5:执行脚本的可读Web外部表db1=# create external web table example5 (linenum int, message text) db1-# execute ‘/home/gpadmin/get_log_data.sh‘ on 5 db1-# format ‘text‘ (delimiter ‘|‘); CREATE EXTERNAL TABLEHAWQ集群中每台主机的相同位置上都必须有同一个可执行的脚本,否则查询会报错,如hdp1上没有/home/gpadmin/get_log_data.sh文件。
db1=# select * from example5; ERROR: external table example5 command ended with error. sh: /home/gpadmin/get_log_data.sh: No such file or directory (seg0 hdp1:40000 pid=360600) DETAIL: Command: execute:/home/gpadmin/get_log_data.sh对该外部表的查询会返回每个虚拟段输出的并集,例如,get_log_data.sh脚本内容如下:
#!/bin/bash echo "1|aaa" echo "2|bbb"则该表将返回10条(每个虚拟段两条,五个虚拟段)数据:
db1=# select * from example5; linenum | message ---------+--------- 1 | aaa 2 | bbb 1 | aaa 2 | bbb 1 | aaa 2 | bbb 1 | aaa 2 | bbb 1 | aaa 2 | bbb (10 rows)执行查询时,资源管理器最少分配5个虚拟段。如果建表时指定的虚拟段数超过了允许的最大值,表仍然可以建立,但查询时会报错。
db1=# drop external web table example5; DROP EXTERNAL TABLE db1=# create external web table example5 (linenum int, message text) db1-# execute ‘/home/gpadmin/get_log_data.sh‘ on 100 db1-# format ‘text‘ (delimiter ‘|‘); CREATE EXTERNAL TABLE db1=# select * from example5; ERROR: failed to acquire resource from resource manager, minimum expected number of virtual segment 100 is more than maximum possible number 64 in queue pg_default (pquery.c:804)例6:执行脚本的可写web外部表
db1=# create writable external web table example6 db1-# (name text, date date, amount float4, category text, desc1 text) db1-# execute ‘PATH=/home/gpadmin/programs; export PATH; myprogram1.sh‘ on 6 db1-# format ‘text‘ (delimiter ‘|‘) db1-# distributed randomly; CREATE EXTERNAL TABLEmyprogram1.sh的内容如下:
#!/bin/bash while read line do echo "File:${line}" >> /home/gpadmin/programs/a.txt done向外部表中插入数据。
db1=# insert into example6 values (‘aaa‘,‘2017-01-01‘,100.1,‘aaa‘,‘aaa‘); INSERT 0 1 db1=# insert into example6 values (‘bbb‘,‘2017-02-01‘,200.1,‘bbb‘,‘‘); INSERT 0 1插入的数据通过管道输出给myprogram1.sh并执行,可以看到插入的数据被写入了a.txt文件。与可读表不同,该文件只在一个HAWQ主机上生成,并且每次插入数据只生成一行。
[gpadmin@hdp4 programs]$ more /home/gpadmin/programs/a.txt File:aaa|2017-01-01|100.1|aaa|aaa File:bbb|2017-02-01|200.1|bbb|5. 使用外部表装载数据
CREATE TABLE expenses_travel (LIKE ext_expenses); INSERT INTO expenses_travel SELECT * FROM ext_expenses WHERE category=‘travel‘;也可以在创建一个新表的同时装载数据:
CREATE TABLE expenses AS SELECT * FROM ext_expenses;
6. 外部表错误处理
可读外部表通常被用于选择数据装载到普通的HAWQ数据库表中。使用CREATE TABLE AS SELECT或INSERT INTO命令查询外部表数据。缺省时,如果数据包含错误,则整条命令失败,没有数据装载到目标数据库表中。INSERT INTO table_with_pkeys SELECT DISTINCT * FROM external_table;
(1)使用单行错误隔离定义外部表
下面的例子在HAWQ表中记录错误记录,并设置错误行阈值为10。db1=# create external table ext_expenses ( name text, date date, amount float4, category text, desc1 text ) db1-# location (‘gpfdist://hdp3:8081/*‘, ‘gpfdist://hdp4:8081/*‘) db1-# format ‘text‘ (delimiter ‘|‘) db1-# log errors into errs segment reject limit 10 rows; CREATE EXTERNAL TABLE
(2)标识无效的CSV文件数据
如果一个CSV文件包含无效格式,错误日志表的rawdata字段可能包含多行。例如,某字段少了一个闭合的引号,后面所有的换行符都被认为是数据中内嵌的换行符。当这种情况发生时,HAWQ在一行数据达到64K时停止解析,并将此64K数据作为单行写入错误日志表,然后重置引号标记,继续读取数据。如果这种情况在处理装载时发生三次,载入文件被认为是无效的,整个装载失败,错误信息为“rejected N or more rows”。(3)表间迁移数据
可以使用CREATE TABLE AS或INSERT...SELECT语句将外部表或web外部表的数据装载到其它非外部表中,数据将根据外部表或web外部表的定义并行装载。如果一个外部表或web外部表数据源有错误,依赖于使用的错误隔离模式,有以下两种处理方式:(1)确认建立了运行hawq load的环境。
它需要依赖某些HAWQ安装中的文件,如gpfdist和Python,还需要通过网络访问所有HAWQ segment主机。(2)创建控制文件。
hawq load的控制文件是一个YAML(Yet Another Markup Language)格式的文件,在其中指定HAWQ连接信息,gpfdist配置信息,外部表选项、数据格式等。例如下面是一个名为my_load.yml的控制文件内容:
--- VERSION: 1.0.0.1 DATABASE: db1 USER: gpadmin HOST: hdp3 PORT: 5432 GPLOAD: INPUT: - SOURCE: LOCAL_HOSTNAME: - hdp4 PORT: 8081 FILE: - /home/gpadmin/staging/*.txt - COLUMNS: - name: text - date: date - amount: float4 - category: text - desc1: text - FORMAT: text - DELIMITER: ‘|‘ - ERROR_LIMIT: 25 - ERROR_TABLE: errlog OUTPUT: - TABLE: t1 - MODE: INSERT SQL: - BEFORE: "INSERT INTO audit VALUES(‘start‘, current_timestamp)" - AFTER: "INSERT INTO audit VALUES(‘end‘, current_timestamp)"注意:
LOCAL_HOSTNAME: - hdp4-1 - hdp4-2
[gpadmin@hdp4 staging]$ more a.txt aaa|2017-01-01|100.1|aaa|aaa bbb|2017-01-02|100.2|bbb|bbb [gpadmin@hdp4 staging]$ more b.txt aaa|2017-03-01|200.1|aaa|aaa bbb|2017-03-02|200.2|bbb|bbb建立目标表和audit表。
db1=# create table t1 ( name text, date date, amount float4, category text, desc1 text ); CREATE TABLE db1=# create table audit(flag varchar(10),st timestamp); CREATE TABLE执行hawq load。
[gpadmin@hdp4 ~]$ hawq load -f my_load.yml 2017-04-05 16:41:44|INFO|gpload session started 2017-04-05 16:41:44 2017-04-05 16:41:44|INFO|setting schema ‘public‘ for table ‘t1‘ 2017-04-05 16:41:44|INFO|started gpfdist -p 8081 -P 8082 -f "/home/gpadmin/staging/*.txt" -t 30 2017-04-05 16:41:49|INFO|running time: 5.63 seconds 2017-04-05 16:41:49|INFO|rows Inserted = 4 2017-04-05 16:41:49|INFO|rows Updated = 0 2017-04-05 16:41:49|INFO|data formatting errors = 0 2017-04-05 16:41:49|INFO|gpload succeeded [gpadmin@hdp4 ~]$查询目标表和audit表。
db1=# select * from t1; name | date | amount | category | desc1 ------+------------+--------+----------+------- aaa | 2017-01-01 | 100.1 | aaa | aaa bbb | 2017-01-02 | 100.2 | bbb | bbb aaa | 2017-03-01 | 200.1 | aaa | aaa bbb | 2017-03-02 | 200.2 | bbb | bbb (4 rows) db1=# select * from audit; flag | st -------+---------------------------- start | 2017-04-05 16:41:44.736296 end | 2017-04-05 16:41:49.60153 (2 rows)
[gpadmin@hdp4 ~]$ psql -h hdp3 -d db1 psql (8.2.15) Type "help" for help. db1=# create table t2 (like t1); NOTICE: Table doesn‘t have ‘distributed by‘ clause, defaulting to distribution columns from LIKE table CREATE TABLE db1=# copy t2 from ‘/home/gpadmin/staging/a.txt‘ with delimiter ‘|‘; COPY 2 db1=# select * from t2; name | date | amount | category | desc1 ------+------------+--------+----------+------- aaa | 2017-01-01 | 100.1 | aaa | aaa bbb | 2017-01-02 | 100.2 | bbb | bbb (2 rows)将表数据卸载到master的本地文件中,如果文件不存在则建立文件,否则会用卸载数据覆盖文件原来的内容。
db1=# copy (select * from t2) to ‘/home/gpadmin/staging/c.txt‘ with delimiter ‘|‘; COPY 2 [gpadmin@hdp3 staging]$ more /home/gpadmin/staging/c.txt bbb|2017-01-02|100.2|bbb|bbb aaa|2017-01-01|100.1|aaa|aaa
(1)以单行错误隔离模式运行COPY。
缺省时,COPY在遇到第一个错误时就停止运行。如果数据含有错误,操作失败,没有数据被装载。如果以单行错误隔离模式运行COPY,HAWQ跳过含有错误格式的行,装载具有正确格式的行。如果数据违反了NOT NULL或CHECK等约束条件,操作仍然是‘all-or-nothing’输入模式,整个操作失败,没有数据被装载。[gpadmin@hdp3 staging]$ more a.txt aaa|2017-01-01|100.1|aaa|aaa bbb|2017-01-02|100.2|bbb|bbb向表拷贝本地文件数据,错误日志表中新增一条数据。
db1=# create table t3 ( name text not null, date date, amount float4, category text, desc1 text ); CREATE TABLE db1=# copy t3 from ‘/home/gpadmin/staging/a.txt‘ db1-# with delimiter ‘|‘ log errors into errtable db1-# segment reject limit 5 rows; NOTICE: Error table "errtable" does not exist. Auto generating an error table with the same name WARNING: The error table was created in the same transaction as this operation. It will get dropped if transaction rolls back even if bad rows are present HINT: To avoid this create the error table ahead of time using: CREATE TABLE <name> (cmdtime timestamp with time zone, relname text, filename text, linenum integer, bytenum integer, errmsg text, rawdata text, rawbytes bytea) NOTICE: Dropping the auto-generated unused error table HINT: Use KEEP in LOG INTO clause to force keeping the error table alive COPY 2 db1=# select * from t3; name | date | amount | category | desc1 ------+------------+--------+----------+------- bbb | 2017-01-02 | 100.2 | bbb | bbb aaa | 2017-01-01 | 100.1 | aaa | aaa (2 rows)修改文件,制造一行格式错误的数据。
[gpadmin@hdp3 staging]$ more a.txt aaa,2017-01-01,100.1,aaa,aaa bbb|2017-01-02|100.2|bbb|bbb再次拷贝数据。与卸载不同,装载会向表中追加数据。
db1=# copy t3 from ‘/home/gpadmin/staging/a.txt‘ db1-# with delimiter ‘|‘ log errors into errtable db1-# segment reject limit 5 rows; NOTICE: Error table "errtable" does not exist. Auto generating an error table with the same name WARNING: The error table was created in the same transaction as this operation. It will get dropped if transaction rolls back even if bad rows are present HINT: To avoid this create the error table ahead of time using: CREATE TABLE <name> (cmdtime timestamp with time zone, relname text, filename text, linenum integer, bytenum integer, errmsg text, rawdata text, rawbytes bytea) NOTICE: Found 1 data formatting errors (1 or more input rows). Errors logged into error table "errtable" COPY 1 db1=# select * from t3; name | date | amount | category | desc1 ------+------------+--------+----------+------- bbb | 2017-01-02 | 100.2 | bbb | bbb bbb | 2017-01-02 | 100.2 | bbb | bbb aaa | 2017-01-01 | 100.1 | aaa | aaa (3 rows) db1=# \x Expanded display is on. db1=# select * from errtable; -[ RECORD 1 ]---------------------------- cmdtime | 2017-04-05 16:56:02.402161+08 relname | t3 filename | /home/gpadmin/staging/a.txt linenum | 1 bytenum | errmsg | missing data for column "date" rawdata | aaa,2017-01-01,100.1,aaa,aaa rawbytes | db1=#再次修改文件,将name字段对应的数据置空,因为该字段定义为NOT NULL,所以违反约束,没有数据被拷贝。
[gpadmin@hdp3 staging]$ more a.txt |2017-01-01|100.1|aaa|aaa bbb|2017-01-02|100.2|bbb|bbb db1=# truncate table t3; TRUNCATE TABLE db1=# copy t3 from ‘/home/gpadmin/staging/a.txt‘ with delimiter ‘|‘ null as ‘‘ log errors into errtable segment reject limit 5 rows; ERROR: null value in column "name" violates not-null constraint (seg5 hdp1:40000 pid=370883) CONTEXT: COPY t3, line 1: "|2017-01-01|100.1|aaa|aaa" db1=# select * from t3; name | date | amount | category | desc1 ------+------+--------+----------+------- (0 rows)
db1=# create writable external table unload_expenses db1-# ( like t1 ) db1-# location (‘gpfdist://hdp3:8081/expenses1.out‘, db1(# ‘gpfdist://hdp4:8081/expenses2.out‘) db1-# format ‘text‘ (delimiter ‘,‘); NOTICE: Table doesn‘t have ‘distributed by‘ clause, defaulting to distribution columns from LIKE table CREATE EXTERNAL TABLE可写外部表只允许INSERT操作。如果执行卸载的用户不是外部表的属主或超级用户,必须授予对外部表的INSERT权限。例如:
GRANT INSERT ON unload_expenses TO admin;与例4不同,INSERT INTO 外部表 SELECT ... 语句中,外部表的输出文件只能在一个主机上,否则会报错。
db1=# insert into unload_expenses select * from t1; ERROR: External table has more URLs then available primary segments that can write into them (seg0 hdp1:40000 pid=387379) db1=# drop external table unload_expenses; DROP EXTERNAL TABLE db1=# create writable external table unload_expenses db1-# ( like t1 ) db1-# location (‘gpfdist://hdp3:8081/expenses1.out‘) db1-# format ‘text‘ (delimiter ‘,‘); NOTICE: Table doesn‘t have ‘distributed by‘ clause, defaulting to distribution columns from LIKE table CREATE EXTERNAL TABLE db1=# insert into unload_expenses select * from t1; INSERT 0 4查看导出的数据。
[gpadmin@hdp3 staging]$ more expenses1.out aaa,2017-01-01,100.1,aaa,aaa bbb,2017-01-02,100.2,bbb,bbb aaa,2017-03-01,200.1,aaa,aaa bbb,2017-03-02,200.2,bbb,bbb [gpadmin@hdp3 staging]$如上面的例6所示,也可以定义一个可写的外部web表,发送数据行到脚本或应用。脚本文件必须接收输入流,而且必须存在于所有HAWQ segment的主机的相同位置上,并可以被gpadmin用户执行。HAWQ系统中的所有segment都执行脚本,无论segment是否有需要处理的输出行。
gp_external_enable_exec = off正如前面说明COPY命令时所看到的,COPY TO命令也可以用来卸载数据。它使用HAWQ master主机上的单一进程,从表中数据拷贝到HAWQ master主机上的一个文件(或标准输入)中。COPY TO命令重写整个文件,而不是追加记录。
(1)行格式
HAWQ需要数据行以换行符(LF,Line feed,ASCII值0x0A)、回车符(CR,Carriage return,ASCII值0x0D)或回车换行符(CR+LF,0x0D 0x0A)作为行分隔符。LF是类UNIX操作系统中标准的换行符。而Windows或Mac OS X使用CR或CR+LF。所有这些表示一个新行的特殊符号都被HAWQ作为行分隔符所支持。(2)列格式
文本文件和CSV文件缺省的列分隔符是分别是TAB(ASCII值为0x09)和逗号(ASCII值为0x2C)。在定义数据格式时,可以在CREATE EXTERNAL TABLE或COPY命令的DELIMITER子句,或者hawq load的控制文件中,声明一个单字符作为列分隔符。分隔符必须出现在字段值之间,不要在一行的开头或结尾放置分隔符。例如,下面使用管道符(|)作为列分隔符:data value 1|data value 2|data value 3下面的建表命令显示以管道符作为列分隔符:
=# CREATE EXTERNAL TABLE ext_table (name text, date date) LOCATION (‘gpfdist://host:port/filename.txt) FORMAT ‘TEXT‘ (DELIMITER ‘|‘);
(3)表示空值
空值(NULL)表示一列中的未知数据。可以指定数据文件中的一个字符串表示空值。文本文件中表示空值的缺省字符串为\N,CSV文件中表示空值的缺省字符串为不带引号的空串(两个连续的逗号)。定义数据格式时,可以在CREATE EXTERNAL TABLE、COPY命令的NULL子句,或者hawq load的控制文件中,声明其它字符串表示空值。例如,如果不想区分空值与空串,就可以指定空串表示NULL。在使用HAWQ装载工具时,任何与声明的代表NULL的字符串相匹配的数据项都被认为是空值。(4)转义
列分隔符与行分隔符在数据文件中具有特殊含义。如果实际数据中也含有这个符号,必须对这些符号进行转义,以使HAWQ将它们作为普通数据而不是列或行的分隔符。文本文件缺省的转义符为一个反斜杠(\),CSV文件缺省的转义符为一个双引号(")。backslash = \\ | vertical bar = \| | exclamation point = !可以对八进制或十六进制序列应用转义符。在装载进HAWQ时,转义后的值就是八进制或十六进制的ASCII码所表示的字符。例如,取址符(&)可以使用十六进制的(\0x26)或八进制的(\046)表示。
ESCAPE ‘OFF‘该设置常用于输入数据中包含很多反斜杠(如web日志数据)的情况。
"Free trip to A,B","5.89","Special rate ""1.79"""将字段值置于双引号中能保留字符串中头尾的空格。
(5)字符编码
在将一个Windows操作系统上生成的数据文件装载到HAWQ前,先使用dos2unix系统命令去除只有Windows使用的字符,如删除文件中的CR(‘\x0d‘)。(6)导入导出固定宽度数据
HAWQ的函数fixedwith_in和fixedwidth_out支持固定宽度的数据格式。这些函数的定义保存在$GPHOME/share/postgresql/cdb_external_extensions.sql文件中。下面的例子声明了一个自定义格式,然后调用fixedwidth_in函数指定为固定宽度的数据格式。db1=# create readable external table students ( db1(# name varchar(5), address varchar(10), age int) db1-# location (‘gpfdist://hdp4:8081/students.txt‘) db1-# format ‘custom‘ (formatter=fixedwidth_in, name=‘5‘, address=‘10‘, age=‘4‘); CREATE EXTERNAL TABLE db1=# select * from students; name | address | age -------+------------+----- abcde | 1234567890 | 40 (1 row)students.txt文件内容如下:
[gpadmin@hdp4 unload_data1]$ more students.txt abcde12345678900040文件中一行记录的字节必须与建表语句中字段字节数的和一致,如上例中一行必须严格为19字节,否则读取文件时会报错。再看一个含有中文的例子。
[gpadmin@hdp4 unload_data1]$ echo $LANG zh_CN.UTF-8 [gpadmin@hdp4 unload_data1]$ more students.txt 中文中文中0040操作系统和数据库的字符集都是UTF8,一个中文占用三个字节,记录一共19字节,满足读取条件。
db1=# select * from students; name | address | age ------+---------+----- 中 | 中文中 | 40 (1 row)name字段5字节,address字段10字节,理论上这两个字段都应该含有不完整的字符,但从查询结果看到,HAWQ在这里做了一些处理,name字段读取了一个完整的中文,address字段读取了三个完整的字符。而中间按字节分裂的中文字符被不可见字符所取代。
db1=# select char_length(name),octet_length(name),substr(name,1,1),substr(name,2,1) from students; char_length | octet_length | substr | substr -------------+--------------+--------+-------- 2 | 5 | 中 | (1 row) db1=# select char_length(address),octet_length(address),substr(address,1,1),substr(address,2,1) from students; char_length | octet_length | substr | substr -------------+--------------+--------+-------- 4 | 10 | | 中 (1 row)以下选项指定如何读取固定宽度数据文件。
line_delim=E‘\n‘ line_delim=E‘\r‘ line_delim=E‘\r\n‘ line_delim=‘abc‘
(2)pg_statistic系统表与pg_stats视图
pg_statistic系统表保存每个数据库表上最后执行ANALYZE操作的结果。每个表列有一行记录,它具有以下字段:SELECT n.nspname AS schemaname, c.relname AS tablename, a.attname, s.stanullfrac AS null_frac, s.stawidth AS avg_width, s.stadistinct AS n_distinct, CASE 1 WHEN s.stakind1 THEN s.stavalues1 WHEN s.stakind2 THEN s.stavalues2 WHEN s.stakind3 THEN s.stavalues3 WHEN s.stakind4 THEN s.stavalues4 ELSE NULL::anyarray END AS most_common_vals, CASE 1 WHEN s.stakind1 THEN s.stanumbers1 WHEN s.stakind2 THEN s.stanumbers2 WHEN s.stakind3 THEN s.stanumbers3 WHEN s.stakind4 THEN s.stanumbers4 ELSE NULL::real[] END AS most_common_freqs, CASE 2 WHEN s.stakind1 THEN s.stavalues1 WHEN s.stakind2 THEN s.stavalues2 WHEN s.stakind3 THEN s.stavalues3 WHEN s.stakind4 THEN s.stavalues4 ELSE NULL::anyarray END AS histogram_bounds, CASE 3 WHEN s.stakind1 THEN s.stanumbers1[1] WHEN s.stakind2 THEN s.stanumbers2[1] WHEN s.stakind3 THEN s.stanumbers3[1] WHEN s.stakind4 THEN s.stanumbers4[1] ELSE NULL::real END AS correlation FROM pg_statistic s JOIN pg_class c ON c.oid = s.starelid JOIN pg_attribute a ON c.oid = a.attrelid AND a.attnum = s.staattnum LEFT JOIN pg_namespace n ON n.oid = c.relnamespace WHERE has_table_privilege(c.oid, ‘select‘::text);新建的表没有统计信息。
(3)采样
在为大表计算统计信息时,HAWQ通过对基表采样数据的方式建立一个小表。如果基表是分区表,从全部分区中采样。样本表中的行数取决于由gp_analyze_relative_error系统配置参数指定的最大可接受错误数。该参数的缺省值是0.25(25%)。通常该值已经足够生成正确的查询计划。如果ANALYZE不能产生好的表列估算,可以通过调低该参数值,增加采样的数据量。注意,降低该值可能导致大量的采样数据,并明显增加分析时间。[gpadmin@hdp3 ~]$ hawq config -s gp_analyze_relative_error GUC : gp_analyze_relative_error Value : 0.25
(4)统计更新
不带参数运行ANALYZE会更新当前数据库中所有表的统计信息,这可能需要执行很长时间。所以最好分析单个表,在一个表中的数据大量修改后分析该表。也可以选择分析一个表列的子集,例如只分析连接、where子句、sort子句、group by子句、having子句中用到的列。db1=# analyze t1 (name,category); ANALYZE
(5)分析分区和AO表
在分区表上运行ANALYZE命令时,它逐个分析每个叶级别的子分区。也可以只在新增或修改的分区文件上运行ANALYZE,避免分析没有变化的分区。[gpadmin@hdp3 ~]$ hawq config -s optimizer GUC : optimizer Value : on [gpadmin@hdp3 ~]$ hawq config -s optimizer_analyze_root_partition GUC : optimizer_analyze_root_partition Value : on每次运行ANALYZE或ANALYZE ROOTPARTITION时,根级别的统计信息被更新。analyzedb应用缺省更新根分区统计。当在父表上使用ANALYZE收集统计信息时,既会收集每个叶子分区的统计信息,又会收集分区表的全局统计信息。生成分区表的查询计划时两个统计信息都需要。如果所有子分区的统计信息都已经更新,ROOTPARTITION选项可用于只收集分区表的全局状态信息,这可以节省分析每个叶子分区所需要的时间。
db1=# analyze rootpartition t1; WARNING: skipping "t1" --- cannot analyze a non-root partition using ANALYZE ROOTPARTITION ANALYZE db1=# analyze rootpartition sales; ANALYZE
$ source /usr/local/hawq/greenplum_path.sh
$ hawq config -c default_statistics_target -v 50
$ hawq stop cluster -u
db1=# alter table t1 alter column desc1 set statistics 0; ALTER TABLE统计目标可以设置为0到1000之间的值,或者设置成-1,此时恢复使用系统缺省的统计目标值。
(2)自动收集统计信息
如果一个表没有统计信息,或者在表上执行的特定操作改变了大量的数据时,HAWQ可以在表上自动运行ANALYZE。对于分区表,自动统计收集仅当直接操作叶表时被触发,它仅分析叶表。[gpadmin@hdp3 ~]$ hawq config -s gp_autostats_mode GUC : gp_autostats_mode Value : ON_NO_STATSon_change模式仅当影响的行数超过gp_autostats_on_change_threshold配置参数设置的阈值时触发ANALYZE,该参数的缺省值为2147483647。
[gpadmin@hdp3 ~]$ hawq config -s gp_autostats_on_change_threshold GUC : gp_autostats_on_change_threshold Value : 2147483647on_change模式可能触发不希望的大的分析操作,严重的会使系统中断,因此不推荐在全局修改该参数,但可以在会话级设置,例如装载数据后自动分析。
$ hawq configure -c gp_autostats_mode -v none如果想记录自动统计收集操作的日志,可以设置log_autostats系统配置蚕食参数为on。
标签:.sh 标准 ace segment 串行化 后台运行 substr more 完数
原文地址:http://blog.csdn.net/wzy0623/article/details/69383685