postgresql - 为什么 PostgreSQL 在从稳定函数调用 volatile 函数时不给出警告?

标签 postgresql stored-procedures volatile

例如:

CREATE TABLE x (
    val double);

CREATE FUNCTION g() RETURNS boolean AS $$
    INSERT INTO x SELECT rand() RETURNING val>0.5;
$$ LANGUAGE SQL VOLATILE;

CREATE FUNCTION f() RETURNS boolean AS $$
    SELECT g();         -- this is where the stability-violation happens
$$ LANGUAGE SQL STABLE; -- this is a lie

根据文档,f() 也应标记为 VOLATILE,因为调用 f() 会产生副作用。 PostgreSQL 没有给出警告(或者更好的是,错误),这让我相信一定有某种原因允许这个“明显”的错误存在。

最佳答案

这是一个非常有趣的问题,我鼓励您在 PostgreSQL 电子邮件列表中接受它。

简短的回答是,这些是由它们所做的事情强制执行的,而不是它们调用的函数。

这允许您做一些相当有趣的事情。例如,假设我想要一个值,它将为每个查询创建一个随机数:

create function rand_im() returns double precision language sql immutable as 
$$ select random(); $$;

现在我有一个不可变的随机数函数,它可以被优化为在查询计划形成之前发生的单个调用,因此可以用来确定索引是否有用:

chris=# explain analyse select * from profile_matches where id > (4 * rand_im());
                                                 QUERY PLAN                     

--------------------------------------------------------------------------------
-----------------------------
 Seq Scan on profile_matches  (cost=0.00..39.10 rows=647 width=12) (actual time=
0.009..0.010 rows=1 loops=1)
   Filter: ((id)::double precision > 3.24490546248853::double precision)
 Total runtime: 0.022 ms
(3 rows)

所以这里我们有一个“不可变”,它调用一个明显易变的函数,这实际上很有用,因为它允许我们创建一个将被扁平化的函数,并且可以为查询提供一个值。

现在,根据另一个链接,我真的不知道调用易变函数的稳定函数会发生什么。据我所知,这只是一个优化问题,保护措施非常少,但我不保证总是允许数据库副作用。

此外,需要考虑的一件简单的事情是函数是规划器不透明的,并且不可能在所有过程语言上都避免这种情况。考虑一下您可能有一个 Java 函数,该函数可以标记为不可变但可以运行查询(这可能不是一件好事)。所以这可能看起来是一个明显的错误,但它实际上是一个潜在有用的错误。

关于postgresql - 为什么 PostgreSQL 在从稳定函数调用 volatile 函数时不给出警告?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18907025/

相关文章:

c# - 在 SQL 中将 LIKE '%' 与整数一起使用

c# - 为什么字符串上的 Thread.VolatileRead 无法编译

c++ - 'volatile' 是否足以阻止 C++ 编译器优化静默写入?

java - 禁用 NamedParameterJdbcTemplate 缓存

database - 在 postgresql 中如何使用 group by 并获取所有列

c# - 如何使用 ADO.NET 调用存储过程?

c - volatile value-only 语句会触发 C 中的读访问吗?

java - Hibernate:合并parentEntity时childEntity null id

sql - 基于逻辑 AND 而不是逻辑 OR 查找关联

mysql根据变量(存储过程)更新不同的行