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


9

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

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

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


以下のサンプルクエリ:


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'))

2
実際のクエリを入力してください。
ypercubeᵀᴹ

「3つのオプション」は、クエリが8つの異なるバリエーションを持つことができることを意味しますか(2、3、4オプションがアクティブかどうかによって異なります)?
ypercubeᵀᴹ

WHEREには4つのANDコンポーネントがあります。st_intersectsは必須ですが、他のものが存在する場合とそうでない場合があります。しかし、それらがすべて存在する場合に対処したいと思います。

2
質問をdba.seに移行することに投票しました。これは複数の範囲条件を持つ複雑なクエリです。
ypercubeᵀᴹ

1
EXPLAIN ANALYZEクエリを表示します。
クレイグリンガー

回答:


4

私の仕事の一環として、かなり大きな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();を選択します。


1
これらは優れたヒントです。私はあなたのアドバイスを取り入れ、これを使用して、私たちが維持しているはるかに大きなテーブル(4300万行)で実験を行いました。結果はである:dba.stackexchange.com/questions/61084/...
Dr.YSG

1

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

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


上記の私の更新を参照してください、しかし私はあなたが私に良いリードを与えていると思います、行の出力を最も速く減らすインデックスの順序付けについて考えてください。そうですか?
Dr.YSG
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.