PostgreSQL 9.6の望ましくないネストループとハッシュ結合


13

PostgreSQL 9.6のクエリ計画に問題があります。私のクエリは次のようになります:

SET role plain_user;

SELECT properties.*
FROM properties
JOIN entries_properties
  ON properties.id = entries_properties.property_id
JOIN structures
  ON structures.id = entries_properties.entry_id 
WHERE structures."STRUKTURBERICHT" != ''
  AND properties."COMPOSITION" LIKE 'Mo%'
  AND (
    properties."NAME" LIKE '%VASP-ase-preopt%'
    OR properties."CALCULATOR_ID" IN (7,22,25)
  )
AND properties."TYPE_ID" IN (6)

上記で使用したテーブルに対して行レベルのセキュリティを有効にしています。

  • を使用するset enable_nestloop = Trueと、クエリプランナーはネストループを実行し、合計実行時間は約37秒になります。https//explain.depesz.com/s/59BR

  • set enable_nestloop = False使用すると、ハッシュ結合メソッドが使用され、クエリ時間は約0.3秒です。https//explain.depesz.com/s/PG8E

VACUUM ANALYZEクエリを実行する前に行いましたが、役に立ちませんでした。

set enable_nestloop = False、およびプランナーにとって他の同様のオプションは良い習慣ではないことを知っています。しかし、ネストされたループを無効にせずにハッシュ結合を使用するようにプランナーを「確信」させるにはどうすればよいでしょうか。

クエリの書き換えはオプションです。

RLSをバイパスするロールで同じクエリを実行すると、非常に高速に実行されます。行レベルのセキュリティポリシーは次のようになります。

CREATE POLICY properties_select
ON properties
FOR SELECT
USING (
  (
    properties.ouid = get_current_user_id()
    AND properties.ur
  )
  OR (
    properties.ogid in (select get_current_groups_id())
    AND properties.gr
  )
  OR properties.ar
);

任意のアイデアや提案をいただければ幸いです。


ただ、少しは混乱:なぜ持っていませんAND properties."TYPE_ID" IN (6);= 6;
Vérace

2
@Véracewhile =はより広く使用されていますが、どちらも同じようにプレーニングされます。私の仮定は、彼が複数の値で遊んでいる、またはORMが少し怠惰であることです。
エヴァンキャロル

回答:


15

ここで起こっていることは、ネストされたループが片側でかなり離れていることです。ネストされたループは働く本当に片側1行を返すような、非常に小さい場合も。クエリでは、プランナーはここを探し回って、ハッシュ結合が1行だけを返すと推定します。代わりに、そのハッシュ結合(property_id = id)は1,338行を返します。これにより、すでに3,444行ある入れ子ループの反対側で1,338ループが強制的に実行されます。これは、1つだけを期待している場合(これは「ループ」ではない)です。とにかく。

下に進むにつれてさらに調べていくと、ハッシュ結合は、これから発生する見積もりによって本当に失敗していることがわかります。

Filter: (((properties."COMPOSITION")::text ~~ 'Mo%'::text) AND (((properties."NAME")::text ~~ '%VASP-ase-preopt%'::text) OR (properties."CALCULATOR_ID" = ANY ('{7,22,25}'::integer[]))))

PostgreSQLはそれが1行を返すことを期待しています。しかし、そうではありません。そして、それは本当にあなたの問題です。ここにいくつかのオプションがあり、そりハンマーを取り出して無効にすることは含まれていませんnested_loop

  • インデックスを1つまたは2つ追加してproperties、seqスキャンを完全にスキップできるようにするか、リターンをより正確に見積もることができます。

    CREATE INDEX ON properties USING ( "TYPE_ID", "CALCULATOR_ID" );
    -- the gist_trgm_ops may or may not be needed depending on selectivity of above.
    CREATE INDEX ON properties USING GIST (
      "COMPOSITION" gist_trgm_ops,
      "NAME"        gist_trgm_ops
    );
    ANALYZE properties;
  • または、プロパティをCTEまたは副選択に移動してOFFSET 0、フェンスを作成することもできます。

    WITH t AS (
      SELECT *
      FROM properties.
      WHERE "COMPOSITION" LIKE 'Mo%'
      AND (
        "NAME" LIKE '%VASP-ase-preopt%'
        OR "CALCULATOR_ID" IN (7,22,25)
      )
      AND "TYPE_ID" IN (6)
    )
    SELECT * FROM structures
    JOIN t ON (
      structures.id = entries_properties.entry_id
    )
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.