postgresql临时表的线程安全性

net*_*tta 5 java postgresql

这是我用于创建临时表的语法:

create temp table tmpTable (id bigint not null, primary key (id)) on commit drop;
Run Code Online (Sandbox Code Playgroud)

我知道这意味着在每个事务结束时,此表将被删除.我的问题是,如果同一会话中的两个或多个线程创建并将值插入临时表,它们每个都会获得自己的实例,还是整个会话中共享的临时实例?如果它是共享的,有没有办法让它在每个线程本地?

谢谢Netta

Erw*_*ter 8

临时表对同一会话中的所有操作都是可见的.所以,你不能创建同名的临时表在同一个会话你放弃存在的一个(提交你的情况的交易)前.

您可能想要使用:

CREATE TEMP TABLE tmptbl IF NOT EXISTS ...
Run Code Online (Sandbox Code Playgroud)

更多关于CREATE TABLE手册.


独特的临时表

要使临时表在每个"线程"本地(在同一会话中),您需要使用唯一的表名.一种方法是使用未绑定的SEQUENCE动态SQL - 使用plpgsql或DO语句等过程语言(在没有存储函数的情况下基本相同).

运行一个:

CREATE SEQUENCE myseq;
Run Code Online (Sandbox Code Playgroud)

使用:

DO $$
BEGIN
EXECUTE 'CREATE TABLE tmp' || nextval('myseq')  ||'(id int)';
END;
$$
Run Code Online (Sandbox Code Playgroud)

要知道最新的表名:

SELECT 'tmp' || currval('myseq');
Run Code Online (Sandbox Code Playgroud)

或者将它全部放入plpgsql函数并返回表或重用表名.

但是,所有其他SQL命令都必须动态执行,因为普通的SQL语句使用硬编码标识符.因此,将它全部放入plpgsql函数中可能是最好的.


使用相同临时表的唯一ID

另一种可能的解决方案是对同一会话中的所有线程使用相同的临时表,thread_id并向表中添加一列.如果您大量使用该功能,请务必为该列编制索引.然后使用thread_id每个线程的唯一(在同一会话中).

只有一次:

CREATE SEQUENCE myseq;
Run Code Online (Sandbox Code Playgroud)

每个线程一次:

CREATE TEMP TABLE tmptbl(thread_id int, col1 int) IF NOT EXISTS;
my_id :=  nextval('myseq'); -- in plpgsql
-- else find another way to assign unique id per thread
Run Code Online (Sandbox Code Playgroud)

SQL:

INSERT INTO tmptbl(thread_id, col1) VALUES
(my_id, 2), (my_id, 3), (my_id, 4);

SELECT * FROM tmptbl WHERE thread_id = my_id;
Run Code Online (Sandbox Code Playgroud)

  • @netta:临时表是会话的*local*.如果要使用相同的名称进行操作,请使用单独的会话.否则你必须使用动态SQL,就像我添加到我的答案中一样.或者每个线程使用一个唯一的ID - 我在回答中添加了另一个想法. (2认同)