Jon*_*noB 9 postgresql performance memory query-performance
我正在尝试从命令行使用 转储大表的全部内容pqsl
,但遇到了内存使用量上升的问题,直到进程被终止,甚至在任何数据被转储之前。
我不明白的是:为什么查询不立即返回结果,并在不耗尽内存的情况下完成?
这是对我正在尝试的确切内容的解释:
我有一张桌子,说:
CREATE TABLE big
(
id integer,
rand double precision
)
Run Code Online (Sandbox Code Playgroud)
插入大量行(5000万):
insert into big
select generate_series(1, 50000000) AS id, random();
Run Code Online (Sandbox Code Playgroud)
选择每一行的查询计划看起来像(并不奇怪):
$ psql -d big -c "explain select * from big;"
QUERY PLAN
----------------------------------------------------------------
Seq Scan on big (cost=0.00..924326.24 rows=50000124 width=12)
(1 row)
Run Code Online (Sandbox Code Playgroud)
然后我尝试将内容转储到文件:
$ psql -d big -c "select * from big;" > big.dump
Run Code Online (Sandbox Code Playgroud)
正如我上面所说,这个命令在写入任何数据之前失败,似乎是在被操作系统杀死之前占用了越来越多的内存(被“OOM 杀手”)。
注意:我知道我可以pg_dump
用来完成类似的事情,但实际上,我的查询比这更复杂 - 具体来说,我想在转储时将每一行编码为 JSON。
一些配置细节:
Dan*_*ité 10
默认情况下,结果完全缓存在内存中,原因有两个:
1) 除非使用该-A
选项,否则输出行是对齐的,因此在 psql 知道每列的最大长度之前无法开始输出,这意味着访问每一行(除了大量内存之外,这还需要大量时间)。
2) 除非指定 a FETCH_COUNT
,否则psql 会PQexec
直接在查询上使用同步函数,它会缓冲整个结果集。但是在设置 a 时FETCH_COUNT
,它将使用基于游标的方法,连续获取调用并释放或重用每FETCH_COUNT
行的客户端缓冲区。
所以一个大的结果集应该通过如下命令获取:
psql -A -t --variable="FETCH_COUNT=10000" \
-c "select columns from bigtable" \
> output-file
Run Code Online (Sandbox Code Playgroud)
随着FETCH_COUNT
降低,如果行是非常大的,它仍然吃太多的记忆。
的-t
代表--tuples-only
,这抑制了页眉和页脚的输出。