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

Create non conflicting temporary tables in a Pl/pgSQL function

我想在 Pl/pgSQL 函数中创建一个 TEMPORARY TABLE,因为我想在执行某些过程之前对其进行索引。对该函数的任何并发调用都会尝试重用相同的 table 这一事实似乎是一个问题。

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

文档说

"Temporary tables are automatically dropped at the end of a session, or optionally at the end of the current transaction"

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

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

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

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

PostgreSQL requires each session to issue its own CREATE TEMPORARY TABLE command for each temporary table to be used. This allows different sessions to use the same temporary table name for different purposes (...)

不同 会话 的临时 table 不能冲突,因为每个会话都有一个专用的临时架构,仅对当前会话可见。

在当前的 Postgres 中,一次只有 一个 事务在同一个会话中运行。因此,只有在 同一会话 中的两次 连续 调用才能看到相同的临时对象。 ON COMMIT DROP,如您所见,将 temp tables 的生命周期限制为当前 事务 ,避免与其他事务发生冲突。

如果您(可以)有临时 tables 不随交易而死(比如如果您想在当前交易结束后继续使用其中一些 tables ),那么如果临时 table 已经存在,则另一种方法是截断而不是创建 - 这也更便宜一些。

包装成一个函数:

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');

如果 table 存在,则假定相同的 table 定义。您可能会做更多事情,还可以 return 提供更多信息,等等。这只是基本概念。

相关: