sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQLがSTABLE/IMMUTABLE関数を複数回呼び出すのはなぜですか?

    テストコードの次の拡張は参考になります:

    CREATE OR REPLACE FUNCTION test_multi_calls1(one integer)
    RETURNS integer
    AS $BODY$
    BEGIN
        RAISE NOTICE 'Immutable called with %', one;
        RETURN one;
    END;
    $BODY$ LANGUAGE plpgsql IMMUTABLE;
    CREATE OR REPLACE FUNCTION test_multi_calls2(one integer)
    RETURNS integer
    AS $BODY$
    BEGIN
        RAISE NOTICE 'Volatile called with %', one;
        RETURN one;
    END;
    $BODY$ LANGUAGE plpgsql VOLATILE;
    
    WITH data AS
    (
        SELECT 10 AS num
        UNION ALL SELECT 10
        UNION ALL SELECT 20
    )
    SELECT test_multi_calls1(num)
    FROM data
    where test_multi_calls2(40) = 40
    and test_multi_calls1(30) = 30
    

    出力:

    NOTICE:  Immutable called with 30
    NOTICE:  Volatile called with 40
    NOTICE:  Immutable called with 10
    NOTICE:  Volatile called with 40
    NOTICE:  Immutable called with 10
    NOTICE:  Volatile called with 40
    NOTICE:  Immutable called with 20
    

    ここでは、select-listで不変関数が複数回呼び出され、where句で1回呼び出され、volatileが3回呼び出されたことがわかります。

    重要なのは、PostgreSQLがSTABLEのみを呼び出すということではありません。 またはIMMUTABLE 同じデータで一度機能します-あなたの例は、これが当てはまらないことを明確に示しています-それはかもしれない 一度だけ呼び出します。または、揮発性バージョンを50回呼び出す必要がある場合は、2回呼び出すこともあります。

    安定性と不変性を利用する方法はさまざまですが、コストとメリットはさまざまです。選択リストを使用して行う必要があると提案している種類の保存を提供するには、結果をキャッシュし、キャッシュされた結果を返すか、キャッシュで関数を呼び出す前に、このキャッシュ内の各引数(または引数のリスト)を検索する必要があります-お嬢。これは、キャッシュヒットの割合が高い場合でも、関数を呼び出すよりもコストがかかります(キャッシュヒットが0%になる可能性があるため、この「最適化」によって余分な作業が行われ、まったく利益が得られませんでした)。最後のパラメータと結果だけを保存することもできますが、それでもまったく役に立たない可能性があります。

    これは、安定した不変の関数が最も軽い関数であることが多いことを考えると、特にそうです。

    ただし、where句を使用すると、test_multi_calls1の不変性が決まります。 PostgreSQLが与えられたSQLの明白な意味から実際にクエリを再構築できるようにします:

    まったく別のクエリプランへ:

    これは、PostgreSQLがSTABLEおよびIMMUTABLEを使用する種類の使用法です。結果のキャッシュではなく、より効率的で同じ結果をもたらす別のクエリへのクエリの書き換えです。

    また、where句にどのような順序で表示されていても、test_multi_calls1(30)はtest_multi_calls2(40)の前に呼び出されることに注意してください。これは、最初の呼び出しで行が返されない場合(= 30を置き換えます)を意味します = 31を使用 テストするために)、揮発性関数はまったく呼び出されません-andのどちら側にあるかに関係なく再び呼び出されます 。

    この特定の種類の書き換えは、不変性または安定性に依存します。 where test_multi_calls1(30) != numを使用 クエリの書き換えは不変に対して行われますが、単に安定した関数に対しては発生しません。 where test_multi_calls1(num) != 30を使用 他の最適化も可能ですが、まったく発生しません(複数回の呼び出し):

    STABLE関数とIMMUTABLE関数のみを含む式は、インデックススキャンで使用できます。 VOLATILE関数を含む式はできません。呼び出しの数は減少する場合と減少しない場合がありますが、さらに重要なことに、呼び出しの結果は、クエリの残りの部分ではるかに効率的な方法で使用されます(大きなテーブルでのみ重要ですが、それは大規模になる可能性があります違い)。

    全体として、メモ化の観点からボラティリティカテゴリを考えるのではなく、PostgreSQLのクエリプランナーに論理的に同等(同じ結果)であるがはるかに効率的な方法でクエリ全体を再構築する機会を与えるという観点から考えてください。



    1. php-mysqlはデータベースから次と前のIDをフェッチします

    2. Mysql日付範囲リストから各日付を生成します

    3. 同じmysqlサーバーの異なるデータベースからテーブルを複製する

    4. SQLiteの日付と時刻