当应用程序可能尝试为独立但同时的进程创建临时表时,使用临时表是否安全?

Is it safe to use temporary tables when an application may try to create them for independent, but simultaneous processes?

我希望我能有效地表达这一点,所以这里是:

我正在创建一个模型,用户可能会同时在平台上 运行,但每个模型 运行 都由一个唯一的整数标识符标记。该模型将执行一系列 PostgreSQL 查询并最终将结果写入 elswehere。

现在,由于模型 运行 需要并行化,我必须确保进程不会发生冲突,尽管 运行 在同一个数据库中。我现在必须存储记录列表,按分数变量排序,然后对它们进行操作。这是查询的开头:

DO
$$
DECLARE row RECORD;
BEGIN

DROP TABLE IF EXISTS ranked_clusters;
CREATE TEMP TABLE ranked_clusters AS (
    SELECT
        pl.cluster_id AS c_id,
        SUM(pl.total_area) AS cluster_score
    FROM
        emob.parking_lots AS pl
    WHERE
        pl.cluster_id IS NOT NULL
        AND
        run_id = 2005149
    GROUP BY
        pl.cluster_id
    ORDER BY
        cluster_score DESC
);

FOR row IN SELECT c_id FROM ranked_clusters LOOP
    RAISE NOTICE 'Cluster %', row.c_id;
END LOOP;

END;
$$ LANGUAGE plpgsql;

所以我创建了一个名为 ranked_clusters 的临时 table,然后遍历它,目前只记录每条记录的标识符。

我一直小心翼翼地只从 run_id 值等于特定数字的记录构建此列表,因此来自同一来源但数字不同的数据将被忽略。

然而,我担心的是,同步进程也会创建自己的 ranked_clusters 临时进程 table,这将与第一个进程发生冲突,从而使结果无效。

所以我的问题本质上是这样的:临时 table 是否仅对创建它们的会话可见(或者对来自 Python 的游标对象可见)?因此,以这种方式使用临时 table 安全吗?

我问的主要原因是因为我看到这些所谓的"temporary" tables似乎在我在PgAdmin III中执行查询后仍然存在,并且在下一次执行时查询失败因为 table 已经存在。这让我很困扰,因为似乎 table 在其生命周期内实际上是全局可访问的,因此当同时发生 运行 时会引入冲突的可能性。

感谢@a_horse_with_no_name的解释,但我还不确定它是否安全,因为我已经能够执行以下代码:

import psycopg2 as pg2

conn = pg2.connect(dbname=CONFIG["GEODB_NAME"],
                       user=CONFIG["GEODB_USER"],
                       password=CONFIG["GEODB_PASS"],
                       host=CONFIG["GEODB_HOST"],
                       port=CONFIG["GEODB_PORT"])
conn.autocommit = True
cur = conn.cursor()

conn2 = pg2.connect(dbname=CONFIG["GEODB_NAME"],
                    user=CONFIG["GEODB_USER"],
                    password=CONFIG["GEODB_PASS"],
                    host=CONFIG["GEODB_HOST"],
                    port=CONFIG["GEODB_PORT"])
conn2.autocommit = True
cur2 = conn.cursor()

    cur.execute("CREATE TEMPORARY TABLE temptable (tempcol INTEGER); INSERT INTO temptable VALUES (0);")
    cur2.execute("SELECT tempcol FROM temptable;")
    print(cur2.fetchall())

我收到了 temptable 中的值,尽管它是作为临时 table 创建的,与之后查询它的连接完全不同。我在这里错过了什么吗?因为看起来临时 table 确实可以在连接之间访问。

上面有一个错字,两个游标实际上都是从 conn 生成的,而不是一个从 conn 另一个从 conn2 生成的。 psycopg2 中的各个连接无法访问彼此的临时 table,但从同一连接生成的游标可以。

临时 table 仅对创建它们的会话(=连接)可见。即使两个会话创建相同的table,它们也不会相互干扰。

会话断开时,临时 table 会自动删除。

如果您想在交易结束时自动删除它们,请在创建 table 时使用 ON COMMIT DROP 选项。

所以答案是:是的,这是安全的。


不相关,但是:您不能存储行 "in a sorted way"。 table 中的行没有隐式排序顺序。获得保证排序顺序的唯一方法是在 选择 行时使用 ORDER BY。作为 CREATE TABLE AS 语句一部分的 order by 几乎没有用。

如果您必须依赖行的排序顺序,唯一安全的方法是在 SELECT 语句中:

FOR row IN SELECT c_id FROM ranked_clusters <b>ORDER BY cluster_score </b>
LOOP
    RAISE NOTICE 'Cluster %', row.c_id;
END LOOP;