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

TSTZRANGEを&&で結合すると、Postgresql9.4クエリの速度が徐々に遅くなります

    除外制約

    代わりに、除外制約を使用することをお勧めします。これは、はるかに簡単、安全、高速です。

    追加のモジュール btree_gist<をインストールする必要があります/ code> 最初。この関連する回答の説明と説明を参照してください:

    また、 "ParentID"を含める必要があります テーブル内"Bar" 冗長に、それは支払うべき小さな価格になります。テーブル定義は次のようになります。

    CREATE TABLE "Foo" (
       "FooID"    serial PRIMARY KEY
       "ParentID" int4 NOT NULL REFERENCES "Parent"
       "Details1" varchar
       CONSTRAINT foo_parent_foo_uni UNIQUE ("ParentID", "FooID")  -- required for FK
    );
    
    CREATE TABLE "Bar" (
       "ParentID"  int4 NOT NULL,
       "FooID"     int4 NOT NULL REFERENCES "Foo" ("FooID"),
       "Timerange" tstzrange NOT NULL,
       "Detail1"   varchar,
       "Detail2"   varchar,
       CONSTRAINT "Bar_pkey" PRIMARY KEY ("FooID", "Timerange"),
       CONSTRAINT bar_foo_fk
          FOREIGN KEY ("ParentID", "FooID") REFERENCES "Foo" ("ParentID", "FooID"),
       CONSTRAINT bar_parent_timerange_excl
          EXCLUDE USING gist ("ParentID" WITH =, "Timerange" WITH &&)
    );

    "Bar"。"FooID"のデータ型も変更しました int8から int4へ 。 "Foo"。"FooID"を参照します 、これは serial 、つまり int4 。一致するタイプint4を使用します (または単に integer )いくつかの理由で、そのうちの1つはパフォーマンスです。

    トリガーはもう必要ありません(少なくともこのタスクでは必要ありません)。また、インデックス "Bar_FooID_Timerange_idx"を作成しません。 除外制約によって暗黙的に作成されるため、これ以上はありません。

    ( "ParentID"、 "FooID")のbtreeインデックス ただし、おそらく役立つでしょう:

    CREATE INDEX bar_parentid_fooid_idx ON "Bar" ("ParentID", "FooID");
    

    関連:

    UNIQUE( "ParentID"、 "FooID")を選択しました "FooID" が先頭にある別のインデックスがあるため、その逆ではありません。 いずれかの表:

    余談ですが、二重引用符で囲まれたCaMeLは使用していません-大文字と小文字の区別 Postgresで。ここでは、レイアウトに準拠するためにのみ行います。

    冗長な列を避ける

    "Bar"。"ParentID"を含めることができない、または含めない場合 冗長に、別の不正があります 方法-"Foo"。"ParentID"という条件で 更新されることはありません 。たとえば、トリガーを使用して、それを確認してください。

    IMMUTABLEを偽造することができます 機能:

    CREATE OR REPLACE FUNCTION f_parent_of_foo(int)
      RETURNS int AS
    'SELECT "ParentID" FROM public."Foo" WHERE "FooID" = $1'
      LANGUAGE sql IMMUTABLE;
    

    public を想定して、確実にテーブル名をスキーマ修飾しました 。スキーマに適応します。

    詳細:

    次に、それを除外制約で使用します:

       CONSTRAINT bar_parent_timerange_excl
          EXCLUDE USING gist (f_parent_of_foo("FooID") WITH =, "Timerange" WITH &&)

    1つの冗長なint4を保存している間 列では、制約の検証に費用がかかり、ソリューション全体がより多くの前提条件に依存します。

    競合の処理

    INSERTをラップできます およびUPDATE plpgsql関数に追加し、除外制約から発生する可能性のある例外をトラップします( 23P01 exclude_violation )何らかの方法で処理します。

    INSERT ...
    
    EXCEPTION
        WHEN exclusion_violation
        THEN  -- handle conflict
    

    完全なコード例:

    Postgres9.5での競合の処理

    Postgresでは9.5 INSERTを処理できます 新しい「UPSERT」実装で直接。 ドキュメント:

    ただし:

    ただし、 ON CONFLICT DO NOTHINGは引き続き使用できます。 、したがって、 exclude_violationの可能性を回避します 例外。実際に更新された行があるかどうかを確認するだけです。これは安価です:

    INSERT ... 
    ON CONFLICT ON CONSTRAINT bar_parent_timerange_excl DO NOTHING;
    
    IF NOT FOUND THEN
       -- handle conflict
    END IF;
    

    この例では、チェックを指定された除外制約に制限します。 (上記の表の定義で、この目的のために制約に明示的に名前を付けました。)他の考えられる例外はキャッチされません。




    1. pgDash DiagnosticsAlternatives-ClusterControlを使用したPostgreSQLクエリ管理

    2. Java/Kotlinから挿入されたH2データベースとMySQLデータベースのDATETIME値の不一致

    3. データベースに複数のアレイを挿入するにはどうすればよいですか?

    4. postgresのクラスター化インデックスについて