web-dev-qa-db-ja.com

Postgresは、結合されたテーブルでこのクエリにインデックスのみのスキャンを使用できますか?

これは次のフォローアップです: PostgreSQLでインデックスをカバーすることは列の結合に役立ちますか?

結合されたテーブルでフィルタリングする他の質問のスキーマの逆を検討してください。

CREATE TABLE thing_types(
   id              INTEGER PRIMARY KEY
 , first_lvl_type  TEXT
 , second_lvl_type TEXT
);

CREATE TABLE things(
   id         INTEGER PRIMARY KEY
 , thing_type INTEGER REFERENCES thing_types(id)
 , t1c1       INTEGER
);

そして、そのようなクエリ:

SELECT things.t1c1
FROM   things
JOIN   thing_types ON things.thing_type = thing_types.id
WHERE  thing_types.first_lvl_type = 'Book'
AND    thing_types.second_lvl_type = 'Biography';

次のようなインデックスを持つことは狂気ですか?

CREATE INDEX ON thing_types(first_lvl_type, second_lvl_type, id);

その結合で使用する主キーをカバーするのはどれですか?インデックスは、上記のクエリでJOINを支援するためのカバリングインデックスとして使用されますか?このようにテーブルがJOINedされることがわかっている場合、主キーをより頻繁にカバーするようにインデックス作成戦略を変更する必要がありますか?

2
ldrg

index-only scanの追加の前提条件が満たされている場合、列idを(先行列としてではなく)後続列としてインデックスに追加するのが最適です。

_CREATE INDEX ON thing_types(first_lvl_type, second_lvl_type, id);
_

Postgres 11は実際の INCLUDEキーワードを使用したインデックスのカバー を導入します。

_CREATE INDEX ON thing_types(first_lvl_type, second_lvl_type) INCLUDE (id);
_

あなたのケースにとってはほんのわずかな利点ですが、UNIQUEまたはPKインデックスまたは制約に列を追加することは素晴らしいオプションです。

インデックスのみのスキャンについて:

最も重要な前提条件:テーブル_thing_types_の可視性マップは、ほとんどまたはすべてのページをすべてのトランザクションに対して「可視」として表示する必要があります。つまりテーブルが読み取り専用であるか、自動バキューム設定が積極的であるので、テーブルへの書き込み後に継続的にクリーンアップできます。

インデックスを追加するたびにコストが追加されます。主にパフォーマンスを記述します。しかし、キャッシュ容量の枯渇などの副作用もあります。 (同じインデックスを使用する複数のクエリは、それらがキャッシュに存在する可能性が高くなります。)したがって、sizeの問題でもあります。 idは通常、非常に小さい列integerまたはbigintです。ユースケースの良い候補にします。

特に、インデックスに列を追加すると、H.O.Tのオプションが無効になります。列を含む更新。ただし、idはとにかくインデックスが付けられ、通常は更新されない(PKであるため)ので、この場合は問題ありません。関連:

ほとんどの場合、これらのインデックスから実際にインデックスのみのスキャンを取得する場合は、通常、それらを使用するのが妥当です。 EXPLAIN でテストします。

以前のバージョンでは部分インデックスに制限がありました。 Postgresのリリースノートを引用9.6

  • インデックスのWHERE句がインデックス付けされていないカラムを参照する場合、部分インデックスで index-only scan の使用を許可します(Tomas Vondra、Kyotaro Horiguchi)

    たとえば、CREATE INDEX tidx_partial ON t(b) WHERE a > 0で定義されたインデックスは、_WHERE a > 0_を指定し、aを使用しないクエリによるインデックスのみのスキャンに使用できるようになりました。以前は、aがインデックス列としてリストされていないため、これは許可されていませんでした。

1

実際に試して、特定のクエリプランを確認する必要があります。あなたは与えられたアドバイスについて多くの包括的な仮定をしており、それがクエリにとって有用である可能性すらあります。

  • サイズ。
  • PostgreSQLメジャー番号
  • コストの構成。
  • 統計の古さと正確さ。

それらすべてが重要です。

ここでは漠然としているわけではありませんが、これを示すいくつかの例を思い付くことができます。

一般に、テーブルで既にインデックスが付けられているものにはインデックスを付けません。インデックスが特定の列をカバーするたびに他の理由がない場合、行を変更するときに更新する必要があるインデックスがもう1つあります。

0
Evan Carroll