PostgreSQL如何创建事务级唯一的TEMP TABLE?
问题描述
我希望在存储函数中实现查询物化,最初尝试使用MATERIALIZED CTE:
WITH cte2 AS MATERIALIZED ( SELECT arg_date, RANK() over(ORDER BY cte1.arg_date DESC) AS DATE_RANK FROM cte1 )
但这样做并没有提升函数性能。随后我改用TEMP TABLE实现:
CREATE OR REPLACE FUNCTION test_f -- 部分代码省略 AS $function$ -- 部分代码省略 begin -- 部分代码省略 CREATE TEMP TABLE cte2 ON COMMIT DROP as with cte1 AS ( SELECT arg_date::date AS arg_date FROM UNNEST(date_array) AS arg_date ) SELECT cte1.arg_date, date_part('year', cte1.arg_date) AS ARG_YEAR, RANK() over(ORDER BY cte1.arg_date DESC) AS DATE_RANK FROM cte1 ; -- 部分代码省略 end; -- 部分代码省略 $function$
改用TEMP TABLE后,函数性能提升了3倍!
现在我需要确认以下几个问题:
- 该TEMP TABLE cte2每次调用存储函数时是否是唯一的?
- PostgreSQL文档提到"PostgreSQL instead requires each session to issue its own CREATE TEMPORARY TABLE command.",且
ON COMMIT DROP会在事务结束时删除TEMP TABLE。但每次事务开始时是否会创建唯一的TEMP TABLE实例? - 每个实例是否仅当前事务可见?
- 该特性是默认生效还是可显式指定?
问题解答
- 每次调用存储函数时,TEMP TABLE cte2是唯一的:PostgreSQL的临时表是会话隔离的,结合
ON COMMIT DROP的特性,每次事务执行到CREATE TEMP TABLE语句时,都会创建全新的临时表实例——即便同名,只要前一个实例已被销毁(事务结束自动删除),新的调用就会生成独立的实例,不会产生冲突。 - 每次事务开始时创建的TEMP TABLE实例是唯一的:临时表本身属于会话级隔离资源,加上
ON COMMIT DROP会在事务结束时自动销毁表,所以每次事务触发函数执行时,都会生成仅属于当前事务的全新临时表实例,与其他事务的实例完全独立。 - 每个临时表实例仅当前事务可见:这是PostgreSQL临时表的默认行为,临时表的可见范围被限定在创建它的会话内,而
ON COMMIT DROP进一步把生命周期缩限到当前事务,其他事务(哪怕是同一会话内的并行事务)都无法访问这个临时表实例。 - 该特性默认生效,无需显式指定:会话隔离、
ON COMMIT DROP的事务级自动销毁都是PostgreSQL临时表的内置行为,只要使用CREATE TEMP TABLE并指定ON COMMIT DROP,这些特性就会自动启用,不需要额外配置。
内容的提问来源于stack exchange,提问作者Иван Размахнин
相关产品推荐
相关产品推荐

