声明:转载必须注明出处
GP的数据导出不应当包含gp_dump,其是一个shell命令,且导出的文件中还包含了恢复时需要的脚本,不属于纯数据文件。
真正可以作为导出数据使用的方法有:可写外部表和Copy,这两种方式也存在一些差异,本文主要讨论两者之间如何选择。
先说说Copy这个SQL命令,Copy有两种选择:Copy一个表对象|COPY一个查询,两者在性能上有显著的差异,笔者猜测可能
与二者的实现有关,对一个表对象直接做Copy操作时,可以将单个文件的写性能发挥到极致,一般可以达到300~400MB/S范围,
近乎单文件读写的CPU性能极限。此时使用系统工具也可以看到,有一个CPU的Core达到了100%的繁忙程度。这绝对是使用者所
期待的,也是Copy整表的优势。Copy作用在一个查询上时,性能有大幅下降,大约在70MB/S,差不多是作用在整表上时性能的
20%,时间被无情的拉长了4倍。因此,Copy更适合整表操作,如果必须要作用在查询语句上,笔者建议:先根据查询生成一个中
间结果表,再将中间结果表Copy出去。
不过,Copy命令本身是没有并发的,因此,对于GP这样的MPP环境来说,绝对不足以应付所有场合,对于超大规模数据需要
被导出的场景很不适合。对于那些较小规模的导出,比如100GB左右的导出,Copy是一个很不错的简单快捷的选择。
再来说说可写外部表,可写外部表与可读外部表都基于gpfdist服务,而性能与可读外部表确有较大差异,单个gpfdist服务的
可读外部表可以达到300~400MB/S的范围,而单个gpfdist服务的可写外部表性能表现较差,笔者没记错的话,与Copy作用在查询
上的性能相当70MB/S左右。不过,在实际应用中,可以使用多个gpfdist配合多个输出文件来提升性能。
下面贴出笔者曾今用Python写的GP Function,用以同时直接连接Segment Instance做Copy导出的代码,由于代码写得时间
稍有些久远,仅作为参考,不完善之处还请包含。该函数借鉴了gp_dump的思路,每个Instance做一份独立的Copy操作,从而确
保性能可以达到极限。
注:如果直接导出到Master上,可能会产生网络拥堵,需慎用。笔者已经考虑重写这方面的函数,用以实现导出到集群外的机
器上,但目前还只在考虑阶段,实现思路在下面的代码中已经完全体现,有兴趣者可以尝试自行实现。至于使用什么语言,笔者认
为,Python或者Perl都是不错的选择。
-
create or replace function gp_toolkit.gp_direct_export(table_name text, delimiter_char char,
directory text,file_pre text, file_tail text,file_format text, batch_size int, is_on_master boolean)
returns setof text as
$body$
import os
import time
import thread
import threading
dbsnm=plpy.execute("select current_database() as dbn")[0]["dbn"]
tblnm=table_name
dlmtr=delimiter_char
drcts=directory.split(',')
tmspn=1.0/batch_size
onmst=is_on_master
flpre=file_pre
fltal=file_tail
flfmt=''
if file_format.lower()=='csv':
flfmt='csv'
def thread_copy(cont,addr,port,drct):
cmr="PGOPTIONS='-c gp_session_role=utility' psql -h "+addr+" -d "+dbsnm+" -p "+port+" <
if onmst:
cmr=cmr+r'\copy '
else:
cmr=cmr+r'copy '
cmr=cmr+tblnm+" to '"+drct+"/"+flpre+"_"+cont+"."+fltal+"' delimiter '"+dlmtr+"' "+flfmt+""
cmr=cmr+"\nEOF"
os.popen(cmr)
thread.exit()
segments_sql="select content::text c,address::text a,port::text p from gp_segment_configuration where content<>'-1' and role<>'m'"
segments_row=plpy.execute(segments_sql)
thread_pool=[]
idx=0
lth=len(drcts)
for seg_row in segments_row:
th=threading.Thread(target=thread_copy,args=(seg_row['c'],seg_row['a'],seg_row['p'],drcts[idx]))
thread_pool.append(th)
idx=idx+1
if idx==lth:
idx=0
yield('START COPY...')
lth=len(thread_pool)
idx=1
for th in thread_pool:
th.start()
if idx
time.sleep(tmspn)
idx=idx+1
for th in thread_pool:
th.join()
yield('COPY COMPLETE...')
$body$
language plpythonu volatile;
声明:转载必须注明出处
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/10109602/viewspace-1184090/
,如需转载,请注明出处,否则将追究法律责任。