根本原因是PostgreSQL服务端执行查询时将全部结果集一次性加载进内存,而非Navicat客户端内存不足;通过设置fetch_size启用游标分批获取,并配合调高work_mem和优化查询,才能有效解决out of memory问题。
Navicat执行查询时触发PostgreSQL的out of memory错误
根本原因不是navicat本身内存不够,而是postgresql服务端在执行查询(尤其是未加limit的全表扫描)时,把整个结果集一次性加载进内存并尝试返回给客户端。postgresql 12默认使用fetch_size = 1(即“逐行拉取”逻辑未启用),但navicat若未显式控制获取节奏,就会让服务端缓存全部结果——这对大表极其危险。
为什么改fetch_size能缓解问题
PostgreSQL支持游标式分批获取(cursor-based fetch),本质是让服务端只保留当前批次的结果在内存中。Navicat底层用的是libpq驱动,它通过fetch_size参数控制每次从服务器取多少行。设为1000或5000后,服务端不再预分配数百万行的内存空间,而是按需构造、发送、释放。
- 默认行为:Navicat发起
SELECT * FROM huge_table→ PostgreSQL启动一个隐式游标 → 尝试把全部结果装入work_mem区域 → 超出即报out of memory - 生效条件:必须在执行前设置,且仅对
SELECT类查询有效;DDL、DML不走此路径 - 注意点:该值不能超过服务端
work_mem单次上限(如设fetch_size=10000但work_mem='4MB',仍可能失败)
在Navicat里怎么设置fetch_size
这个参数不在图形界面选项中暴露,需通过连接高级配置注入。操作路径如下:
- 右键已保存的PostgreSQL连接 → 编辑连接 → 切换到
高级标签页 - 在
连接字符串输入框末尾追加:options=-c%20statement_timeout%3D30000%20-c%20fetch_size%3D2000 - 其中
%20是空格URL编码,%3D是等号编码;数值建议从1000起步,逐步试探 - 保存后**必须重启该连接**(关闭再重连),否则不生效
验证是否生效:执行SHOW statement_timeout; SHOW fetch_size;(PostgreSQL 12+支持SHOW fetch_size),应返回你设的值。
配合PostgreSQL侧调优才真正可靠
光调Navicat端的fetch_size只是半解。如果服务端work_mem太小(如默认4MB),即使分批取,每批构造中间结果仍可能爆内存。关键要同步检查:
- 登录PostgreSQL执行:
SHOW work_mem;,若低于8MB,考虑在postgresql.conf中调高(例:work_mem = '16MB') - 确认查询是否走了索引:
EXPLAIN ANALYZE SELECT * FROM huge_table WHERE ...,避免因全表扫描导致每批都扫全表 - 禁用Navicat的“自动计算行数”功能(设置 → 常规 → 取消勾选
Count rows when opening a table),否则它会在后台偷偷发COUNT(*)
真正卡住的点往往藏在服务端配置和查询写法里,fetch_size只是打开游标机制的钥匙,不是万能内存压缩器。


















