7

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

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

EDIT1:我正在确保 csv 文件没有以任何方式出现格式错误。我通过尝试将所有拆分的 csv 文件加载到 postgres 中来做到这一点。如果都可以加载,那么这表明这里的问题不太可能是由于 csv 文件格式错误。我已经发现了一些问题。尚不确定这些问题是否会在尝试加载大型 csv 时导致字符串缓冲区错误。

4

1 回答 1

7

原来是一个格式错误的 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 行带有无效的 utf8 字节序列。删除这些行后,9GB 的大 csv 加载得很好。

最初加载大文件时得到无效的字节序列错误会很好。但至少一旦我开始隔离问题,它们就会出现。

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

于 2012-12-17T04:46:38.507 回答