【问题标题】:How to create a temporary cache/table in postgres that lasts the duration of a query如何在 postgres 中创建一个持续查询持续时间的临时缓存/表
【发布时间】:2014-02-11 09:39:18
【问题描述】:

我有一个使用非常昂贵的 plsql 函数进行大量递归计算的查询:

SELECT a, b, expensive_recursion(c, d, e) FROM my_table

函数expensive_recursion() 的plpgsql 是这样的:

CREATE OR REPLACE FUNCTION expensive_recursion(col varchar, parent varchar, date varchar)
RETURNS integer AS
$BODY$
DECLARE
  _value integer;
  _rec record;
BEGIN

  -- get the value for the current parent that matches the range
  EXECUTE 'SELECT value_'||col||' FROM foo WHERE foo.id = '||quote_literal(parent)||' AND foo.range = '||quote_literal(range) INTO _value;


  -- get all children of parent and sum their values
  FOR rec IN EXECUTE 'SELECT child FROM relationships WHERE parent = '||quote_literal(parent) LOOP
    _value = _value + expensive_recursion(col, rec.child, range);
  END LOOP;
  RETURN _value;

END;
$BODY$
LANGUAGE plpgsql STABLE COST 1000;

虽然这可行,但我希望不仅为当前正在递归的行启用缓存,还为当前查询中的所有行启用缓存,并在查询完全执行后清除缓存。

例如,带有一些伪代码的原始函数: 创建或替换函数昂贵的递归(col varchar,父 varchar,范围 varchar) 返回整数 AS $身体$ 宣布 _value 整数; _rec 记录; 开始

  -- pseudo-code to check the cache and get the cached value or insert into cache
  IF parent AND range IN cache
    RETURN SELECT value FROM cache WHERE cache.parent = parent and cache.range = range;
  END IF;

  -- get the value for the current parent that matches the range
  EXECUTE 'SELECT value_'||col||' FROM foo WHERE foo.id = '||quote_literal(parent)||' AND foo.range = '||quote_literal(range) INTO _value;


  -- get all children of parent and sum their values
  FOR rec IN EXECUTE 'SELECT child FROM relationships WHERE parent = '||quote_literal(parent) LOOP
    _value = _value + expensive_recursion(col, rec.child, range);
  END LOOP;

  -- put new value in cache
  INSERT INTO cache (value, parent, range) VALUES (_value, parent, range);

  -- final value with sum for parent and its children
  RETURN _value;
END;
$BODY$
LANGUAGE plpgsql STABLE COST 1000;

有没有办法做到这一点并创建/删除缓存?我可以使用临时表还是我在 plpgsql 函数中管理的某些结构/类型。诀窍是多个用户可以执行此功能,并且由于特定于应用程序的原因,缓存不能跨查询共享。

【问题讨论】:

    标签: sql postgresql caching


    【解决方案1】:

    您可以像普通表一样创建临时表;只需相应地限定它:

    create temporary table ( … );
    

    http://www.postgresql.org/docs/current/static/sql-createtable.html

    这样做有微小的缺点和潜在的主要优点。不利的一面是,如果临时集很小,您将在目录中创建并随后删除行,并在需要清理的过程中添加死行。好处是,如果临时集很大,您可以在其上创建索引,并最终在继续查询之前analyze 表。

    您可以使用定义中的on commit 来控制是在事务结束时还是在会话结束时删除临时表。

    此外,执行递归查询的另一种方法是使用 CTE,也称为 with 查询:

    http://www.postgresql.org/docs/current/static/queries-with.html

    出于所有意图和目的,它创建了一个匿名(和非索引)临时表。您可以递归地执行此操作,这样做效率很高。

    Methinks 尝试更改您的查询和底层逻辑,以便首先尝试使用 CTE。如果一切都失败了,那么看看实际使用临时表。

    【讨论】:

      猜你喜欢
      • 2021-04-29
      • 2011-01-25
      • 2012-04-24
      • 2012-11-15
      • 1970-01-01
      • 1970-01-01
      • 2013-07-02
      • 2011-10-07
      • 2021-03-20
      相关资源
      最近更新 更多