You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何同PostgreSQL查询在Express正常,fs写入时触发磁盘空间不足错误?

问题

我在Node.js应用中使用node-postgres PG客户端查询数据库,将结果传递给Express.js响应时一切正常。但因查询耗时较长,我希望通过cron任务将结果保存到文件,再由Express接口返回该文件。然而使用fs.writeFile或fs.createWriteStream时,却触发了PG Client Error: error: could not write to file "base/pgsql_tmp/pgsql_tmp6554.0": No space left on device错误。想知道为何同一个PostgreSQL查询在Express中可以正常运行,在使用fs写入文件时却不行?

相关代码示例如下:

定时任务代码

const { getData } = require("./pg_queries"); 
const fs = require("fs");
const cron = require("node-cron");

const pull_and_save = async () => {
 fs.writeFile(
    "data/results.json",
    JSON.stringify(await getData()),
    { flag: "w+" },
    (err) => {
      if (err) console.log(err);
    }
  );
}

cron.schedule("* */10 * * * *", function () {
  pull_and_save();
});

Express接口代码

const { getData } = require("./pg_queries"); 
const app = express();

app.get("/get-pg-data", async (req, res) => {
  const data = await getData();
  res.send(data);
});
分析与解决方案

核心原因:数据处理逻辑导致PostgreSQL临时空间占用差异

两种场景下PostgreSQL处理查询结果的方式完全不同:

  • Express接口场景:res.send(data)是流式传输——node-postgres会逐步把查询结果的行数据返回给Node.js,Express再逐段发给客户端,PostgreSQL不需要在临时文件中缓存完整结果集,临时空间占用极低。
  • 定时任务场景:JSON.stringify(await getData())会先把完整结果集全量加载到Node.js内存,这个过程中node-postgres会让PostgreSQL把所有查询结果先写入临时文件(当结果集超过work_mem配置时),再一次性读取到Node.js内存。如果结果集极大,临时文件会快速占满PostgreSQL所在磁盘的空间,触发"No space left on device"错误。

解决办法

  1. 流式处理查询结果,避免全量加载到内存
    修改getData函数,使用node-postgres的流式API,直接把结果逐行写入文件,不用先把所有数据读到内存:

    // pg_queries.js 示例
    const { Pool } = require('pg');
    const pool = new Pool();
    
    async function getData(writeStream) {
      const client = await pool.connect();
      try {
        const resultStream = client.query('SELECT * FROM your_table').stream();
        let isFirstRow = true;
        writeStream.write('[');
        
        resultStream.on('data', (row) => {
          if (!isFirstRow) writeStream.write(',');
          isFirstRow = false;
          writeStream.write(JSON.stringify(row));
        });
    
        return new Promise((resolve, reject) => {
          resultStream.on('end', () => {
            writeStream.write(']');
            writeStream.end();
            resolve();
          });
          resultStream.on('error', reject);
        });
      } finally {
        client.release();
      }
    }
    

    然后修改定时任务代码:

    const pull_and_save = async () => {
      const writeStream = fs.createWriteStream('data/results.json', { flags: 'w+' });
      await getData(writeStream);
    };
    

    这种方式下,PostgreSQL会逐行返回数据,不需要生成大的临时文件,同时Node.js内存占用也会大幅降低。

  2. 调整PostgreSQL配置优化临时空间
    如果必须一次性获取全量结果,可以:

    • 增大work_mem参数:让PostgreSQL在内存中处理结果,避免写入临时文件,但注意不要设置过大导致数据库OOM。
    • 修改temp_tablespaces参数:把临时文件存储到空间更大的磁盘分区。
  3. 修正cron执行频率
    你的cron表达式* */10 * * * *是每10分钟的每秒都执行一次,会短时间内多次触发查询,叠加占用临时空间。改成0 */10 * * *(每10分钟执行一次),避免重复执行导致的资源耗尽。


内容的提问来源于stack exchange,提问作者giddy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 11:57:50