在我的设置中,尝试将大型 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 时导致字符串缓冲区错误。