首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么PL/pgSQL函数会产生副作用,而SQL函数却不能呢?

为什么PL/pgSQL函数会产生副作用,而SQL函数却不能呢?
EN

Stack Overflow用户
提问于 2018-06-23 20:57:22
回答 2查看 1K关注 0票数 1

PostgreSQL文档说:

在执行任何一个SQL函数之前都会对它的整个体进行解析。函数可以包含改变系统目录(例如CREATE TABLE)的命令,但是在解析函数中的后续命令时,这些命令的效果是不可见的。因此,例如,如果将CREATE TABLE foo (...); INSERT INTO foo VALUES(...); 打包到单个SQL函数中,则不会按需要工作,因为解析INSERT命令时foo还不存在。 在这种情况下建议使用PL/pgSQL而不是SQL函数。

  • 为什么“在这种情况下建议使用PL/pgSQL而不是SQL函数”,其中PL/pgSQL或SQL函数包含更改系统目录的命令,如CREATE TABLE foo (...); INSERT INTO foo VALUES(...);
  • “SQL函数的整个主体在执行任何SQL函数之前都会被解析”。对于PL/pgSQL函数不是这样吗?SQL函数和PL/pgSQL函数在解析和执行它们体内的命令方面有什么不同?
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-06-26 01:56:32

你自己用粗体显示了手册中的关键句子

一个SQL函数的整个主体在执行任何一个.之前都会被解析。

还可以读到关于在手册中的文章。

它由两个主要部分组成:解析器和转换过程。引用手册:

转换过程将解析器返回的树作为输入,并执行所需的语义解释,以理解查询引用了哪些表、函数和操作符。

如果SQL函数包含以下命令:

代码语言:javascript
复制
CREATE TABLE foo (...);
INSERT INTO foo VALUES(...);

这两个语句实际上是在同一时间计划的(基于系统目录的相同快照)。因此,INSERT无法看到表"foo“可能是用前面的CREATE命令创建的。这会造成()以下问题之一

  1. 如果没有其他名为"foo“search_patch (尚未)的表,Postgres在尝试创建函数时会抱怨: 错误:关系"foo“不存在
  2. 如果search_patch中已经存在另一个名为"foo“的表(并且不使用相互冲突的列名),Postgres将根据该预先存在的表规划INSERT。通常,如果任何值导致(错误!)中的冲突,则在执行时导致错误!表格。或者,如果运气不好,它甚至可以在没有错误消息的情况下写入该表!很狡猾的虫子。

这在sequentially. PL/pgSQL函数中是不可能发生的,因为它将命令视为准备好的语句、计划好的和执行的。因此,每个语句都可以看到以前语句中创建的对象。

因此,从未访问过的语句甚至从未计划过--与SQL函数不同。语句的执行计划可以在同一个会话中缓存--也不同于SQL函数。阅读手册中关于PL/pgSQL函数中的计划缓存的详细信息。

对于某些用例,每种方法都有其优点。进一步读:

票数 2
EN

Stack Overflow用户

发布于 2018-06-23 21:57:30

在定义时解析Plpgsql函数并检查语法,然后在第一次执行时生成计划。

https://www.postgresql.org/docs/current/static/plpgsql-implementation.html#PLPGSQL-PLAN-CACHING

然后用给定的参数执行该计划。

除了第一次执行时已经存在的文件外,临时文件似乎像预期的那样工作。

如前所述,使用动态SQL (EXECUTE)是阻止计划器访问任意表的一种方法。

https://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51004980

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档