2012-12-16 127 views
5

在我的设置中,PostgreSQL 9.2.2在尝试将大型csv文件加载到表中时似乎出错。PostgreSQL加载大型csv文件到表中时遇到问题

的CSV文件的大小是〜9GB

下面是我用做批量加载的SQL语句:

copy chunksBase (chunkId, Id, chunk, chunkType) from path-to-csv.csv' delimiters ',' csv 

这里有一个几分钟后,我得到的错误:

pg.ProgrammingError: ERROR: out of memory 
DETAIL: Cannot enlarge string buffer containing 1073723635 bytes by 65536 more bytes. 
CONTEXT: COPY chunksbase, line 47680536 

我认为缓冲区不能分配超过1GB,这使我认为这可能是postgresql.conf问题。

这里的postgresql.conf中的注释的行:

bash-3.2# cat postgresql.conf | perl -pe 's/^[ \t]*//' | grep -v '^#' | sed '/^$/d' 
log_timezone = 'US/Central' 
datestyle = 'iso, mdy' 
timezone = 'US/Central' 
lc_messages = 'en_US.UTF-8'   # locale for system error message 
lc_monetary = 'en_US.UTF-8'   # locale for monetary formatting 
lc_numeric = 'en_US.UTF-8'   # locale for number formatting 
lc_time = 'en_US.UTF-8'    # locale for time formatting 
default_text_search_config = 'pg_catalog.english' 
default_statistics_target = 50 # pgtune wizard 2012-12-02 
maintenance_work_mem = 768MB # pgtune wizard 2012-12-02 
constraint_exclusion = on # pgtune wizard 2012-12-02 
checkpoint_completion_target = 0.9 # pgtune wizard 2012-12-02 
effective_cache_size = 9GB # pgtune wizard 2012-12-02 
work_mem = 72MB # pgtune wizard 2012-12-02 
wal_buffers = 8MB # pgtune wizard 2012-12-02 
checkpoint_segments = 16 # pgtune wizard 2012-12-02 
shared_buffers = 3GB # pgtune wizard 2012-12-02 
max_connections = 80 # pgtune wizard 2012-12-02 
bash-3.2# 

没有明确设置一个缓冲到1GB。

这是怎么回事?即使解决方案是增加postgresql.conf中的缓冲区,为什么postgres似乎尝试将单个副本调用中的整个csv文件批量加载到ram中?人们会认为加载大型csv文件是一项常见任务;我不能成为第一个遇到这个问题的人;所以我认为postgres会处理分块的负载,所以缓冲区限制从来没有达到过。

作为一种解决方法,我将csv拆分为较小的文件,然后为每个文件调用副本。这似乎工作正常。但这不是一个特别令人满意的解决方案,因为现在我必须维护要加载到postgres中的每个大型csv的拆分版本。必须有更合适的方式将大型csv文件批量加载到postgres中。

编辑1:我正在确保csv文件不以任何方式格式不正确。我正在通过尝试将所有拆分csv文件加载到postgres中来完成此操作。如果全部都可以加载,那么这表明这里的问题不可能是由于csv文件格式错误造成的。我已经发现了一些问题。还不确定这些问题是否在尝试加载大型csv时导致字符串缓冲区错误。

+1

我怀疑你的CSV格式不正确 - 或者更具体地说,不符合你在'COPY'命令中指定的格式。有关详细信息,请参见[CSV处理文档](http://www.postgresql.org/docs/current/static/sql-copy.html#AEN66692)。你的CSV有一个不匹配的'''字符吗? – willglynn

+0

我认为它是单引号或双引号和字符串的问题。一些字符串值没有正确终止或文本值内有单个字符(例如...不是...),我敢打赌第二个。无论如何这就是为什么Postgres试图缓冲更大的字符串,然后它最初保存在csv文件中。 – Wojtas

+0

我首先检查CSV文件中的(最大)行长度。 BTW:这是遗传/ DNA数据吗? – wildplasser

回答

5

原来是一个畸形的csv文件。

我把大的csv分成更小的块(每个块有100万行),并开始将每个块加载到postgres中。

我开始更多的信息错误:

pg.ProgrammingError: ERROR: invalid byte sequence for encoding "UTF8": 0x00 
CONTEXT: COPY chunksbase, line 15320779 

pg.ProgrammingError: ERROR: invalid byte sequence for encoding "UTF8": 0xe9 0xae 0x22 
CONTEXT: COPY chunksbase, line 369513 

pg.ProgrammingError: ERROR: invalid byte sequence for encoding "UTF8": 0xed 0xaf 0x80 
CONTEXT: COPY chunksbase, line 16602 

共有5列无效UTF-8字节序列,出几百万元的人。删除这些行后,大9GB csv加载得很好。

最初在加载大文件时得到无效的字节序列错误本来是很好的。但至少他们在我开始孤立这个问题后就出现了。

请注意,最初加载大文件时错误中提到的行号与加载较小csv子集文件时发现的编码错误没有关系。初始行号是文件中发生1GB数据的点,因此与1GB缓冲区分配错误有关。但是,这个错误与真正的问题无关......

+0

您可能想要提交一个错误报告以获取错误的错误消息 –

+0

Oracle也有更丰富的导入l sql * loader,它具有更强大的错误处理能力。使用Postgre我通常将所有数据加载到登台表中,这些登台表具有使用TEXT数据类型创建的所有列。这样我就可以将所有的数据加载到数据库中,然后运行不同的查询来查找数据问题。 – Kuberchaun

+0

顺便说一句,它需要多长时间从这样一个大文件复制数据postgres? – DataGreed