在Pl / pgSQL函数中创建非冲突的临时表

时间:2017-09-27 15:05:58

标签: postgresql plpgsql

我想在 Pl / pgSQL 函数中创建一个TEMPORARY TABLE,因为我想在做一些处理之前将其编入索引。对函数的任何并发调用将尝试重用同一个表这一事实似乎是一个问题。

e.g。对函数的第一次调用会创建并使用名为"test"的临时表,其数据取决于函数参数。第二个并发调用还尝试创建和使用具有相同名称但具有不同数据的临时表...

医生说

  

"临时表会在会话结束时自动删除,   或者可选地在当前交易结束时#34;

我想如果使用"ON COMMIT DROP"选项创建的临时表只对当前事务可见,则问题不会存在。是这种情况吗?

如果没有,如何从两个不同的函数调用中自动创建独立的表?

我可能会尝试创建一个临时名称,并检查一个具有此名称的表是否已经存在,但这对我来说似乎有很多管理......

2 个答案:

答案 0 :(得分:2)

临时表仅在当前会话中可见。并发进程即使在共享相同名称时也看不到彼此的临时表。每the documentation:

  

PostgreSQL要求每个会话为要使用的每个临时表发出自己的CREATE TEMPORARY TABLE命令。这允许不同的会话为不同的目的使用相同的临时表名(...)

答案 1 :(得分:1)

不同会话的临时表不会发生冲突,因为每个会话都有一个专用的临时架构,只对当前会话可见。

在当前的Postgres中,只有一个事务一次在同一个会话中运行。因此,同一会话中只有两个连续调用可以看到相同的临时对象。与您发现的一样,ON COMMIT DROP会将临时表的生命周期限制为当前的事务,从而避免与其他事务冲突。

如果你(可以)拥有不会因事务而死的临时表(比如你想在当前事务结束后继续使用其中一些表),那么另一种方法是截断而不是如果临时表已经存在则创建 - 这也便宜一点。

包装成一个功能:

CREATE OR REPLACE FUNCTION f_create_or_trunc_temp_table(_tbl text, OUT _result "char") AS
$func$
BEGIN
   SELECT INTO _result  relkind
   FROM   pg_catalog.pg_class
   WHERE  relnamespace = pg_my_temp_schema()          -- only temp objects!
   AND    relname = _tbl;

   IF NOT FOUND THEN                                  -- not found
      EXECUTE format('CREATE TEMP TABLE %I(id int)', _tbl);

   ELSIF _result = 'r' THEN                           -- table exists
      EXECUTE format('TRUNCATE TABLE %I', _tbl);      -- assuming identical table definition

   ELSE                                               -- other temp object occupies name
      RAISE EXCEPTION 'Other temp object of type >>%<< occupies name >>%<<', _result, _tbl;
      -- or do nothing, return more info or raise a warning / notice instead of an exception
   END IF;
END
$func$  LANGUAGE plpgsql;

呼叫:

SELECT f_create_or_trunc_temp_table('my_tbl');

如果表存在,则假设相同的表定义。你可以做更多,也可以返回更多信息,等等。这只是基本概念。

相关: