3

例えば:

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() を呼び出すと副作用が発生するため、 f() も VOLATILE とマークする必要があります。PostgreSQL は警告 (またはエラー) を出さないので、この「明らかな」間違いが存在するのには何らかの理由があるに違いないと思います。

4

1 に答える 1

2

これは非常に興味深い質問であり、PostgreSQL メーリング リストで取り上げることをお勧めします。

簡単に言えば、これらは呼び出した関数ではなく、実行内容によって強制されるということです。

これにより、かなり興味深いことができます。たとえば、クエリごとに 1 つの乱数を作成する値が必要だとします。

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)

したがって、ここには明らかに揮発性の関数を呼び出す「不変」があり、これは実際に便利です。これにより、フラット化される関数を作成でき、クエリに正確に 1 つの値を提供できるからです。

さて、他のリンクによると、揮発性関数を呼び出す安定した関数に関して何が起こるか本当にわかりません。私が知る限り、これは単なる最適化であり、保護は最小限ですが、db の副作用が常に許可されるとは限りません。

さらに、考慮すべき簡単なことは、関数がプランナーに不透明であり、すべての手続き型言語でこの種のことを防ぐことはできないということです。不変であるとラベル付けされる可能性があるが、クエリを実行できる Java 関数を使用できると考えてください (これはおそらく良いことではありません)。したがって、これは明らかな間違いのように思えるかもしれませんが、実際には潜在的に役立つものです。

于 2013-09-20T05:57:34.077 に答える