copy

官方的里子:https://gpdb.docs.pivotal.io/6-8/ref_guide/sql_commands/COPY.html

能导入到stdin、stdout中,也能导出到具体的文件中。

普通导入

导出

copy table to '/tmp/table.csv';
copy (select * from table where ... group by ... order by ...) to '/tmp/table.csv';

导入

copy table to '/tmp/table.csv';

例子

ON SEGMENT

这个命令是加强命令,很适合多个机器之间传数据。

导出到csv文件

具体执行的命令

COPY tu_doc_info TO PROGRAM 'cat > /tmp/tu_doc_info<SEGID>.csv' ON SEGMENT CSV;
COPY tu_doc_info TO '/tmp/tu2<SEGID>.csv' ON SEGMENT CSV;

以上两种方式,都尝试过了,两次导出的文件。还不一样。每个SEGID文件记录数还不太一样。

上述SEGID变量,gp会识别,并转换成具体的序列好。

csv文件到gp

COPY tu_doc_info FROM '/tmp/tu2<SEGID>.csv' ON SEGMENT CSV;

尝试直接加载未经处理的数据:

COPY tu_doc_info FROM '/path/20200701/tu_doc_info_20200701<SEGID>0500.csv' ON SEGMENT CSV;

错误信息:

ERROR:  value of distribution key doesn't belong to segment with ID 11, it belongs to segment with ID 14  (seg11 10.181.86.12:55011 pid=54103)
CONTEXT:  COPY tu_doc_info, line 1: 

总结: 它说 你把别的分区的数据给我了 。

所以,这个应该是同等数目的节点 升级 、保存之类的

忽略错误

对于一个csv文件,如果存在乱码,或者导入的csv文件中的字段过长,无法导入,其特性是,整体导入成功,或者整体导入失败。这个特性很好,如果发现出错了,我们可以重新再导致那个文件。

但是,它也能忽略错误,并记录到日志中。测试发现,确实能实现。

copy mytable from '$filename' with csv LOG ERRORS SEGMENT REJECT LIMIT 10 ROWS;
-- 或者百分比  PERCENT 

上面能达到,即使出错了,未达到它的容忍度的时候,依然能导入成功数据。

SEGMENT REJECT LIMIT 10 ROWS; 是指节点超过这个度吗?还是说整体?

  • 查看错误日志

    SELECT * from gp_read_error_log('table');
  • 清空日志

    SELECT gp_truncate_error_log('table'); 

    然后再从错误日志中恢复到记录中。

PROGRAM

该关键字能调用shell命令调用shell

-- 以前无法解决的乱码问题,下面命令直接解决了。
COPY tu_doc_info FROM PROGRAM 'iconv -f UTF-8 -t UTF-8  /etl/dta/20200701/tu_doc_info_20200701010500.csv'  CSV;

-- 前面的命令
COPY tu_doc_info TO PROGRAM 'cat > /tmp/tu_doc_info<SEGID>.csv' ON SEGMENT CSV;
COPY LINEITEM_4 FROM PROGRAM 'cat /tmp/lineitem_program<SEGID>.csv' ON SEGMENT CSV;

这个应该类似于管道命令符号一样。它能和linux系统里面的管道符号结合在一起。

分组统计,如何能将一次查询的结果,按照不同的分组(如省,或时间)分组到不同的文件中?难到要自己写shell?

copy来导入数据

利用stdin、stdout在两个数据库之间,传递数据。

https://blog.csdn.net/weixin_39540651/article/details/115494761

!/bin/bash
psql \
    -X \
    -U user_name \
    -h host_name1 \
    -d database_name \
    -c "\\copy tbl_students to stdout" \
|  \
psql \
    -X \
    -U user_name \
    -h host_name2 \
    -d database_name \
    -c "\\copy tbl_students from stdin"

如,保存为copy_data.sh,则执行的时候,执行sh copy_data.sh

copy导出数据到多个文件

比如,分组。如果分组不太多的话,则写多个copy的命令,但是,为每个分组,都要写一个where条件,这个条件,可能要重复计算。(为了减少where时的全表扫描,则,可以建立一个分组表,然后,每次一个分组,即可。)(那么,如何根据多种条件,来建立分组呢?比如范围、或者其他)

另外,如果将产生的数据输出到STDOUT,然后,在shell里面读入数据,然后决定写入到不同的文件,理论上应该也是行的?那么,又如何操作呢?

待研究。