postgresql - 为什么 postgresql 写入巨大的临时文件并在循环中填满我的磁盘?

标签 postgresql performance postgis postgresql-9.3 bigdata

问题: 该函数(下面,在 PostgreSQL 9.3 中)在几次迭代后运行良好,但在多次迭代后,每次迭代都会在磁盘上写入约 1 GB 的文件,直到磁盘已满,并且然后代码以 failed to write 结束。

问题:有没有办法不把这些文件写到磁盘上?或者找到其他方法来规避这个问题?理想情况下,我想让代码运行一整夜,以便在第二天分析结果。

表格应该在每次迭代时被覆盖,所以我不明白为什么它填满了我的磁盘。在我之前的尝试中,它也耗尽了内存,但我在 postgresql.conf 中从 64 增加了 max_locks_per_transaction = 256

我在做什么:

我有一个函数可以获取控制内部循环的参数:开始和结束时间戳、时间 bin delta 时间 span 和时间 jump .像这样: SELECT ib_run2('2009-06-28 13:30:00', '2009-06-29 13:50:59', '10 分钟', '0.5 小时', '24 小时' );

因此该函数将开始和停止之间的时间划分为 bins,在此示例中,从 2009-06-28 13:30:00 开始的时间被划分为 10 分钟 间隔0.5 小时 然后跳 24 小时 并再次跳到 2009-06-29 13:50:59

对于每个 10 分钟的 bin,都会在时空数据集上进行一些计算,包括按时间和位置进行选择以及计算距离。

在函数内部,不可避免地会顺序扫描一个大表(6,154,794 行)和几个较小的表,并从每个表中选择一个子集。该函数对这些子集执行计算并将结果写入创建的表中。

所有表都是使用 CREATE TABLE 创建的。以 IB_000_ 开头的表在循环之前创建,并在循环内用 INSERT INTO 更新。以 IB_i_ 开头的表在每次迭代的循环中被删除并重新创建。

IB_i_ 表的计算涉及在同一迭代中创建的其他IB_i_ 表或用于计算的外部表。

函数:

CREATE OR REPLACE FUNCTION ib_run2(
        start_dt TEXT DEFAULT '2009-06-28 13:30:00'
      , end_dt   TEXT DEFAULT '2009-06-28 13:59:59'
      , deltat   TEXT DEFAULT '10 minute'
      , spant    TEXT DEFAULT '2 hour'
      , jump_txt TEXT DEFAULT '24 hour'
  ) RETURNS TEXT AS
$func$
      DECLARE n INT DEFAULT 1; DECLARE m INT DEFAULT 1; DECLARE iteration INT DEFAULT 0;
      DECLARE delta INTERVAL; DECLARE span INTERVAL; DECLARE jump INTERVAL;
      DECLARE mytext TEXT DEFAULT 'iMarinka';
      DECLARE start_time_query TIMESTAMP DEFAULT now();
      DECLARE dt0 TIMESTAMP;
      DECLARE dt1 TIMESTAMP;
      DECLARE dt TIMESTAMP;
BEGIN
    dt0:=start_dt :: TIMESTAMP;
    dt1:=end_dt :: TIMESTAMP;
    delta:=deltat :: INTERVAL;
    span:=spant :: INTERVAL;
    jump:=jump_txt :: INTERVAL;
    iteration:=0;

    n:=ceiling(extract(EPOCH FROM (dt1-dt0)          )*1.0/extract(EPOCH FROM (jump ) ));
    m:=ceiling(extract(EPOCH FROM ( (dt0+span) -dt0) )*1.0/extract(EPOCH FROM (delta) ));

    DROP TABLE IF EXISTS IB_000_times;
    CREATE TABLE IB_000_times (
              gid serial primary key, i INT, j INT
            , t_from_v TIMESTAMP, t_to_v TIMESTAMP
            , t_from_c TIMESTAMP, t_to_c TIMESTAMP
            , t_day TEXT, date_t DATE, t TIME
            , delta_t INTERVAL
            , dt0 TIMESTAMP, dt1 TIMESTAMP
            , dt TIMESTAMP, delta INTERVAL, span INTERVAL , jump INTERVAL );

    mytext:=(m+1)*(n+1)||' iterations '||n+1||' of i '||m+1||' of j'; RAISE NOTICE '%', mytext;

    FOR i IN 0..n LOOP  -----------------------------------------
    FOR j IN 0..m LOOP  -----------------------------------------

      dt := dt0 + j * delta + i * jump;
      iteration := iteration + 1;

      DROP TABLE IF EXISTS IB_i_times; 
      CREATE TABLE IB_i_times AS (
        WITH a AS (SELECT dt::DATE date_t, dt::TIME t , delta delta_t)
        SELECT date_t+ t - delta_t AS t_from_v
          , date_t+ t AS t_to_v
          , date_t+ t AS t_from_c
          , date_t+ t + delta_t AS t_to_c
          , to_char(date_t, 'day') AS t_day
          , a.date_t , a.t, a.delta_t
        FROM a
      );

      INSERT INTO IB_000_times (i , j,
          t_from_v , t_to_v , t_from_c , t_to_c , t_day , date_t , t , delta_t ,
          dt0 , dt1 , delta , span , jump , dt)
      SELECT i,j, t.t_from_v, t.t_to_v, t.t_from_c, t.t_to_c, t.t_day, t.date_t, t.t, t.delta_t ,
            dt0 , dt1 , delta , span , jump , dt
      FROM IB_i_times t;

      COPY ( select * FROM IB_000_times ) TO '/Volumes/1TB/temp/IB_000_times.csv' CSV HEADER DELIMITER ';' ;

      mytext := iteration||'/'||(n+1)*(m+1)||' -----> '||'   dt= '||to_char(dt,'YYYY-MM-DD HH24:MI:SS'); RAISE NOTICE '%', mytext;
      mytext := 'Fin '||': i='||i||', dt='|| to_char(dt,'YYYY-MM-DD HH24:MI:SS')||', started  '||start_time_query;

    END LOOP;----------------------------------------------------
    END LOOP;----------------------------------------------------
  RETURN mytext;
END;
$func$
LANGUAGE plpgsql;

除了表 IB_i_timesIB_000_times 之外,函数之前还创建了一堆其他表(此处未显示以节省空间,代码有约 500 行) (和一些内部)循环和循环内的更新。

最佳答案

很难说,为什么 Postgres 会从这个源代码生成临时文件。使用日志临时文件 - log_temp_files - 当您识别生成临时文件的语句时,您可以找出原因。通常它是有限的 work_mem

Controls logging of temporary file names and sizes. Temporary files can be created for sorts, hashes, and temporary query results. A log entry is made for each temporary file when it is deleted. A value of zero logs all temporary file information, while positive values log only files whose size is greater than or equal to the specified number of kilobytes. The default setting is -1, which disables such logging. Only superusers can change this setting. https://www.postgresql.org/docs/current/static/runtime-config-logging.html

关于postgresql - 为什么 postgresql 写入巨大的临时文件并在循环中填满我的磁盘?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42862783/

相关文章:

sql - 选择一个小于今天的日期

java - 使用 c3p0 的 JDBC url 中的应用程序名称

postgresql - Apache Spark : JDBC connection not working

postgresql - 如何在复合类型文字中指定 PostGIS 地理值?

postgresql - 如何在 postgres 的插入触发器函数中引用 data_table

performance - 我如何故意从主内存与缓存中读取?

php - 在 Ruby、Python 或 PHP 中,是否有一个插入到 Array 对象中间需要 O(1) 时间的操作?

c# - 空指针测试性能

postgresql - ST_Overlaps 和 ST_intersects

python - 在 postgis 中存储多边形和几何图形