web-dev-qa-db-ja.com

PostgreSQLの複合インデックスの列の順序(およびクエリの順序)

5万行のテーブルがあります。これは実際にはPostGISテーブルです。

クエリには4つの部分があります(1つは必須)(3つはオプション)

  1. 4緯度、経度の交差ボックス(地理長方形)(st_intersectsを使用)[必須]
  2. 日付フィールドの日付範囲(最小、最大)
  3. 現在IN(.....)を使用しているファイルタイプ(最大8つのテキスト値のセット)ですが、必要に応じて一時テーブルにすることができます。 INが嫌いな人が多いようです。
  4. 国(テキスト値)。

返される行は約100-4,000になると思います

テーブルに複合インデックスを作成する場合、どの列を最初に使用する必要がありますか。きめ細かいのはおそらく場所です(データは世界中に広がっています)。現在、Gistインデックスとして持っています。

他のインデックスはBTREEです。

私の直感は、きめ細かい、そして最後のコースを使用すると言います。例えば。約12のファイルタイプしかないため、インデックスのバケットは非常に大きくなります。

PostgreSQLとPostGISの達人(システムの内部を知っている人)は何と言っていますか?


更新:

この質問をもっとはっきりさせましょう。

  1. やるべきことを誰かにやらせてもらいたくない。あなたの時間を尊重しすぎます。ですから、後で説明します。
  2. 私が探していたのは、いくつかの指針とヒント、およびガイドラインだけでした。
  3. 私はこの優れた小さな投稿を読みます: https://devcenter.heroku.com/articles/postgresql-indexes#managing-and-maintaining-indexes インデックスについて
  4. 私が通常行うことは、4つの個別のインデックス(ジオボックス、国名、file_type、および日付)を作成することですが、複合クエリが何を行うかを確認したいのです。

これらの仮定のいずれかが間違っているかどうか教えてください。 (私は複合インデックスのアイデアにかなり新しいです)

  1. 順序は重要です。最初のインデックスとして、行を最も削減するインデックスを選択します(私の場合、場所(地理)は単純なポリゴンまたはマルチポリゴンが最も効果的です)。
  2. クエリはインデックスをスキップすることがあります。しかし、キー(#1、#2、#3、#4)を使用して複合クエリを作成した場合、ユーザーが#1、#3を要求するものを作成した場合でも、プランナーは単一の複合クエリを使用します。維持されている。
  3. 通常、3つのBTREEクエリと1つのGist(geographyタイプ用)を作成します。 PostGISは、複数のインデックスタイプからの複合の作成をサポートしていません。したがって、Gistは複合インデックスを使用する必要があります。しかし、それは物事を傷つけるべきではありません。
  4. 追加の複合インデックスまたは単一値インデックスを作成する場合、プランナーは最もインテリジェントなインデックスを選択するのに十分スマートです。
  5. 国名は約250の異なる値を持つことができ、明らかに場所(ジオボックス)に強くリンクされていますが、行サイズを削減するための次善のインデックスがfile_typeの場合は、次に使用する必要があります。ユーザーがクエリセットで国や日付を頻繁に使用するとは思わない。
  6. 4つのキーの複合インデックスを作成すると、インデックスデータのサイズが大幅に増加することを心配する必要はありません。つまり1つのキーのインデックスがパフォーマンス向上の90%になる場合でも、さらに3つのアイテムを追加して複合させることは問題ありません。逆に、実際には両方のインデックスを作成する必要があります。単一の地理インデックスと複合インデックス。プランナーにどちらが最適かを判断させ、インデックステーブルのサイズを考慮します。

繰り返しになりますが、私は誰かに私のソリューションを設計するように依頼しているのではなく、他の人の作業についてぶつかっていません。しかし、PostGreSQLドキュメントが実装について教えてくれないことが必要です

[まだ表示するEXPLAIN結果がないのは、24Mの行テーブルからこの25Kの行テーブルを作成する必要があるためです。思ったより時間がかかります。私はものを1,000個のアイテムグループにクラスター化し、ユーザーに25K行テーブルに対してクエリを実行させています。しかし、次の質問では、そのクエリの結果を使用してMASTER 25M行テーブルに移動し、物事を引き出します。そのため、複合インデックスのパフォーマンスが実際に低下します。


以下のサンプルクエリ:


SELECT
    public.product_list_meta_mv.cntry_name       AS country,
    public.product_list_meta_mv.product_producer AS producer,
    public.product_list_meta_mv.product_name     AS prod_name,
    public.product_list_meta_mv.product_type     AS ptype,
    public.product_list_meta_mv.product_size     AS size,
    ST_AsGeoJSON(public.product_list_meta_mv.the_geom, 10, 2)          AS outline
FROM
    public.product_list_meta_mv 
WHERE
    public.product_list_meta_mv.cntry_name = 'Poland' 
AND
    ST_Intersects(public.product_list_meta_mv.the_geom,
    st_geogfromtext('SRID=4326;POLYGON((21.23107910156250 51.41601562500000,
                                        18.64379882812500 51.41601562500000,
                                        18.64379882812500 48.69415283203130,
                                        21.23107910156250 48.69415283203130,
                                        21.23107910156250 51.41601562500000))')) 
AND (date >= '1/2/1900 5:00:00 AM' 
 AND date <= '2/26/2014 10:26:44 PM')
AND (public.product_list_meta_mv.product_type in
    ('CIB10','DTED0','DTED1','DTED2','CIB01','CIB05')) ;

EXPLAIN ANALYZEの結果(複合インデックスを入れていないため、表示されている速度から、必要かどうかわかりません)。

"Bitmap Heap Scan on catalog_full cat  (cost=4.33..37.49 rows=1 width=7428) (actual time=1.147..38.051 rows=35 loops=1)"
"  Recheck Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"  Filter: (((type)::text = ANY ('{CADRG,CIB10,DTED1,DTED2}'::text[])) AND (_st_distance('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography, outline, 0::double precision, false) < 1e-005::double precision))"
"  Rows Removed by Filter: 61"
"  ->  Bitmap Index Scan on catalog_full_outline_idx  (cost=0.00..4.33 rows=8 width=0) (actual time=0.401..0.401 rows=96 loops=1)"
"        Index Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"Total runtime: 38.109 ms"

EXPLAIN ANALYZE SELECT pid,product_name,type,country,date,size,cocom,description,egpl_date,ST_AsGeoJSON(outline, 10, 2) AS outline 
FROM portal.catalog_full AS cat 
WHERE ST_Intersects(st_geogfromtext('SRID=4326;POLYGON((21.2200927734375 51.38031005859375, 18.65478515625 51.38031005859375, 18.65478515625 48.7298583984375, 21.2200927734375 48.7298583984375, 21.2200927734375 51.38031005859375))'), cat.outline) 
AND (cat.type in ('CADRG','CIB10','DTED1','DTED2'))
9
Dr.YSG

私の仕事の一環として、かなり大きなPostgreSQLデータベース(ディスク上に約120GB、数百万行のテーブル)を維持し、クエリを高速化する方法に関するいくつかのトリックを収集しました。最初に、仮定についていくつかコメントします。

  1. はい、順序は重要ですが、実際に異なるのは最初のものだけで、残りは2番目のクラスのインデックスです。
  2. 私はそれが常に両方を使用するかどうか確信がありません、私の推測はクエリプランナーが#1を使用し、残りで賢い何かをすることです。
  3. Gistの経験はありません。
  4. はい、最初にすべてのインデックスを追加し、最もよく使用されるものと最高のパフォーマンスを提供するものを確認します。
  5. 両方を試して、何が最も効果的かを測定することをお勧めします。異なるサブクエリを使用してSQLを書き直してみてください。国と時間を1つにまとめてから、intersect-queryに参加してください。 INリストが数千の要素の長さでない限り、IN句のパフォーマンスの問題に気づきませんでした。私の推測では、利用可能な入力基準に応じて特別に調整されたいくつかの異なるクエリが最良の結果をもたらすと思います。
  6. 4ウェイインデックスを作成しないことをお勧めします。作成してサイズを確認してください。非常に大きくなる可能性があります。私の経験では、4つの1キーインデックスは、単一の4ウェイインデックスとほぼ同じ速さでした。特定のクエリでうまく機能するトリックは、部分インデックスです。つまり、次のようなものです。

    CREATE INDEX ON table_x(key1、key2、key3)WHERE some_x_column = 'XXXX';

追加または削除するインデックスの検索に役立つクエリを使用して、.psqlrcファイルにエイリアスを作成しました。 GitHubで自由に見てください: 。psql

:seq_scansと:bigtablesを頻繁に使用し、\ d table_nameを使用してテーブルの詳細を取得します。いくつかの変更を行った後、統計をリセットすることを忘れないでください、pg_stat_reset();を選択します。

4
Claes Mogren

(もしあれば)最も役立つ可能性が高いのは、Gistインデックスの2番目の列としてproduct_typeを追加することだと思います。しかし、典型的な/問題のあるクエリのAND条件のそれぞれに(いくつも)一致する行の数がわからなければ、推測することしかできません。

これに近づくと、最初に行うことは、単純化された形式でクエリを実行することです。ここで、WHERE句には1つの条件のみがあり、それぞれがEXPLAIN ANALYZEで順番に実行されます。それぞれの推定行と実際の行の両方を見てください。

1
jjanes