我希望我能有效地阐明这一点,所以就这样:
我正在创建一个模型,该模型将由用户在平台上运行,可能会同时运行,但是每个运行的模型都由唯一的整数标识符标记。该模型将执行一系列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
的临时表,然后对其进行遍历,此刻只记录了每个记录的标识符。
我一直很谨慎,只从run_id
值等于某个数字的记录构建此列表,因此来自同一来源但具有不同数字的数据将被忽略。
但是,我担心的是,同时进行的进程还会创建自己的ranked_clusters
临时表,该表将与第一个临时表冲突,从而使结果无效。
所以我的问题本质上是:临时表仅对创建临时表的会话(或从Python等游标对象可见)吗?因此,以这种方式使用临时表是否安全?
我问的主要原因是因为我在PgAdmin III中执行查询后发现这些所谓的“临时”表似乎仍然存在,并且由于该表已经存在,因此在下一次执行时查询失败。这让我感到困扰,因为似乎这些表在生命周期中实际上是可以全局访问的,因此当同时运行时,可能会导致冲突。
感谢@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
中的值创建为一个临时表,但该连接与随后查询它的连接完全不同,但我仍收到了该值。我在这里想念什么吗?因为似乎临时表确实可以在连接之间访问。
上面有一个错字,实际上是从conn
产生了两个游标,而不是从conn
产生了一个游标,而从conn2
产生了一个游标。 psycopg2中的各个连接无法访问彼此的临时表,但是从同一连接中产生的游标可以访问。
答案 0 :(得分:3)
临时表仅对创建它们的会话(=连接)可见。即使两个会话创建相同的表,它们也不会互相干扰。
会话断开连接后,临时表将自动删除。
如果要在交易结束时自动删除它们,请在创建表时使用ON COMMIT DROP
选项。
所以答案是:是的,这很安全。
不相关,但是:您不能“以排序的方式”存储行。表中的行没有隐式排序顺序。获得有保证的排序顺序的唯一方法是在选择行时使用ORDER BY
。您的CREATE TABLE AS语句中的order by
几乎没有用。
如果必须依赖行的排序顺序,那么唯一安全的方法是在SELECT语句中
FOR row IN SELECT c_id FROM ranked_clusters ORDER BY cluster_score
LOOP
RAISE NOTICE 'Cluster %', row.c_id;
END LOOP;