强制PostgreSQL在函数中使用不同的模式

强制PostgreSQL在函数中使用不同的模式,postgresql,plpgsql,dynamic-sql,search-path,Postgresql,Plpgsql,Dynamic Sql,Search Path,我想为PG SQL数据库中的模式创建一个更新函数。下面是一个测试函数。它不起作用,因为它不应该发出通知,但在运行test_schema_update'second'时会发出通知 问题在于PG SQL似乎在每个会话中只分析一次SELECT语句,然后将表固定到特定的模式。有趣的是,您将得到的模式是:second 那么,有没有一种方法可以重置SELECT语句分析或其他方法来解决这个问题 旁注:所有模式创建函数ALTERTABLE,CREATETABLE。。。干得好。只有数据操作功能似乎受到选择、插入和

我想为PG SQL数据库中的模式创建一个更新函数。下面是一个测试函数。它不起作用,因为它不应该发出通知,但在运行test_schema_update'second'时会发出通知

问题在于PG SQL似乎在每个会话中只分析一次SELECT语句,然后将表固定到特定的模式。有趣的是,您将得到的模式是:second

那么,有没有一种方法可以重置SELECT语句分析或其他方法来解决这个问题

旁注:所有模式创建函数ALTERTABLE,CREATETABLE。。。干得好。只有数据操作功能似乎受到选择、插入和更新的影响

变通办法 之前:

IF (
    SELECT max(id) FROM dimtime
)
THEN
    INSERT INTO dimtime SELECT * FROM public.src_dimtime;
END IF;
之后:

EXECUTE ('
    SELECT max(id) FROM dimtime
')
INTO testInt;
IF (testInt IS NULL)
THEN
    EXECUTE 'INSERT INTO dimtime SELECT * FROM public.src_dimtime';
END IF;

编辑:问题出现在PostgreSQL 9.2中,但似乎没有出现在9.3中。也许它是固定的?

这种行为是意料之中的。原因是PL/pgSQL对SQL语句使用计划缓存,内部使用标准的准备语句

由于每个表达式和SQL命令首先在函数中执行, PL/pgSQL解释器使用 SPI管理器的SPI_准备和SPI_保存计划功能。后来的 对该表达式或命令的访问将重用准备好的计划

这也是plpgsql函数在复杂操作中通常比普通SQL函数更快的原因:

准备好的语句会在会话的生命周期内保存,不仅仅是事务,而且在底层对象更改时会失效,这对于并发访问是安全的

在PL/pgSQL为特定命令制定了执行计划后 函数,它将在数据库的生命周期中重用该计划 联系这通常是性能的胜利,但它可能导致 如果动态更改数据库模式,可能会出现一些问题

我的

如果您想更改表名的模式,您实际上要引用一个完全不同的表,并且需要使用动态SQL with EXECUTE,它每次都会生成一个新的计划,具有所有优点和缺点:

因为PL/pgSQL以这种方式保存执行计划,所以SQL命令 直接出现在PL/pgSQL函数中必须引用相同的表 以及每一次执行的专栏;也就是说,不能将参数用作 SQL命令中表或列的名称。绕开这件事 限制,您可以使用PL/pgSQL构造动态命令 EXECUTE语句-以构建新的执行计划为代价 每一次处决

阅读手册中的参考章节。它相当全面

代码示例 添加的代码示例不需要动态SQL,单个语句的速度更快:

INSERT INTO dimtime  -- you may want list columns
SELECT *             -- here as well
FROM   public.src_dimtime
WHERE  NOT EXISTS (SELECT 1 FROM dimtime);

这种语法只允许设置静态模式,而不是从参数设置;dump please s1:=当前_模式vs.在s2中执行“选择当前_模式”&标记特定的postgres版本-不要使用不会重新设置以前配置的重置,默认设置将被恢复,在开始时使用set LOCAL,这样您就可以保留重置。谢谢。我已经设法解决了这个限制,但在我的问题中添加的示例中,对所有内容执行都是非常痛苦的。@Nux:您不需要对所有内容执行。只有表/列动态更改的语句。您问题中的示例可以是简单的SQL,也可以是简化的。我在回答中加了一点,一次更新很多模式。换句话说,有client1.dimtime、client2.dimtime等等。我的目标是尽可能多地使用SQL。在另一个函数中,我从信息_schema.schemata获取模式名称。因此,INSERT必须在schema_update函数中,并且必须在特定架构的上下文中调用。@Nux:是的,在这种情况下需要动态SQL。但是使用我的简化查询。一个查询要比两个查询便宜得多。
INSERT INTO dimtime  -- you may want list columns
SELECT *             -- here as well
FROM   public.src_dimtime
WHERE  NOT EXISTS (SELECT 1 FROM dimtime);