如何在postgres中创建一个持续查询持续时间的临时缓存/表

时间:2014-01-21 16:46:02

标签: sql postgresql caching

我有一个非常昂贵的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;

虽然这有效,但我想不仅为当前行进行缓存,而是为当前查询中的所有行启用缓存,并在查询完全执行后清除缓存。

例如,原始函数带有一些伪代码:     创建或替换函数expensive_recursion(col varchar,parent varchar,range varchar)     RETURNS整数AS     $ BODY $     宣布       _value整数;       _rec记录;     BEGIN

  -- 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函数中管理的某些结构/类型。诀窍是多个用户可以执行此功能,并且出于特定于应用程序的原因,不能跨查询共享缓存。

1 个答案:

答案 0 :(得分:1)

您可以像普通表一样创建临时表;相应地符合条件:

create temporary table ( … );

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

这样做有微小的下行空间和潜在的重大上行空间。缺点是,如果临时集很小,那么您正在创建并随后删除目录中的行,并在流程中添加死行,然后需要对其进行清理。好处是,如果临时集很大,你可以在它上面创建一个索引并最终analyze表,然后继续查询它。

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

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

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

对于所有意图和目的,它创建一个匿名(和非索引)临时表。你可以递归地做到这一点,这样做可以相当有效。

Methinks尝试更改您的查询和基础逻辑,以便首先尝试使用CTE。如果所有其他方法都失败了,那么请考虑实际使用临时表。