複合インデックスは、最初のフィールドのクエリにも適していますか?


86

フィールドAとを持つテーブルがあるとしましょうBA+ Bで定期的にクエリを作成するため、で複合インデックスを作成しました(A,B)。クエリAも複合インデックスによって完全に最適化されますか?

さらに、にインデックスを作成しましたAが、Postgresはでのみクエリに複合インデックスを使用していAます。前の答えが正の場合、それは実際には重要ではないと思いますが、単一のAインデックスが利用可能な場合、デフォルトで複合インデックスを選択するのはなぜですか?


私はこれのために小さなテストをセットアップしようとしました。ただし、私の場合、2列のインデックスは、最初に作成されたインデックスとは関係なく、1列のインデックスを削除したときにのみ使用されました。2列のインデックスを最初に作成した場合、最初の計画でビットマップヒープスキャンが使用されたことは興味深いことです。1列のインデックスを作成した後、クエリを実行し(インデックススキャンを使用)、新しく作成したインデックスを削除すると、2列のインデックスを含むプランがインデックススキャンに切り替わりました。SQLFiddle
dezso

@dezso興味深い。各クエリのコストはどこにありますか?
ルチアーノ

ビットマップインデックススキャンコスト:107.98、実行時間43ミリ秒。インデックススキャン1列:コスト8.69、2列:43.69。実行時間に大きな違いはありません(変動は2つの間の差よりも大きい)。
-dezso

@Luciano explain analyzeとクエリテキストを表示できますか?
クレイグリンガー

回答:


88

確かにそうです。この関連する質問の下で詳細に議論しました。

スペースはの倍数で割り当てられMAXALIGNます。これは通常、64ビットOSでは8バイト、32ビットOSでは(あまり一般的ではないが)4バイトです。不明な場合は、を確認してくださいpg_controldata。また、インデックス付き列のデータ型(一部にはアライメントパディングが必要)および実際のコンテンツにも依存します。

たとえば、2つのinteger列(各4バイト)のインデックスは、通常、1つだけのインデックスとまったく同じサイズになり、アライメントパディングのために別の4バイトが失われます。

そのような場合には上のインデックスを使用するクエリプランナには欠点が本当にありません(a,b)-ちょうど上のインデックスに比べて(a)。一般に、複数のクエリで同じインデックスを使用することをお勧めします。共有されると、その(またはその一部)が(高速)キャッシュに常駐する可能性が高まります。

のインデックスを既に保持している場合(a,b)、それだけで別のインデックスを作成することは意味がありません(a)- 大幅に小さい場合を除きます。vs.に同じことが当てはまりません。詳細については、最初の行のリンクに従ってください。(b,a)(a)

反対方向から来て、そのような追加のインデックスが必要な場合は、可能であれば(a,b)既存のインデックスを削除することを検討して(a)ください。多くの場合、これはPKまたはUNIQUE制約のインデックスであるため不可能です。Postgres 11以降bでは、INCLUDE代わりに句を使用して制約定義に追加するだけで済みます。マニュアルの詳細。

または(b,a)代わりに新しいインデックスを作成して、クエリをb追加でカバーします。等価条件の場合のみ、btreeインデックスのインデックス式の順序は関係ありません。ただし、範囲条件が関係する場合は実行されます。見る:

アライメントパディングで失われたスペースのみを使用する場合でも、インデックスに追加の列を含めることには潜在的な欠点があります。

  • 追加の列が更新されるたびに、インデックスの更新も必要になります。これにより、書き込み操作にコストがかかり、インデックスの膨張が増える可能性があります。
  • テーブルのHOT更新(ヒープのみのタプル)は、インデックス列が関係している間は実行できません。

HOTアップデートの詳細:

オブジェクトサイズの測定方法:


1
これを拡張して、列Aにインデックスがあり、複合インデックス(A、B)を追加する必要が生じた場合、インデックスAを削除する必要があると言えますか?インデックスを再利用してキャッシュの効率を改善し、(A、B)Aを完全に最適化すると、Aにインデックスを追加するとスペースが無駄になり、処理速度が低下する可能性があります
jvans

1
@jvans:一般的に正しい-注目すべき例外と代替手段があります。それに対処するために段落を追加しました。
アーウィンブランドステッター

2

質問によると、フィールドAとBを持つテーブルがあります。クエリが次の場合:

SELECT * FROM [YOUR TBL]
WHERE A='XXXX'

オプティマイザは、抽出ランダムアクセスを回避するために複合インデックスを選択します!


-4

述語で最初に使用するだけの場合です。

複合キーの最初の列と複合キーの非キー列を使用する場合、スキャンを実行します。

それをだますために、このようなダミーの述語だけでなく、非キー列を使用できます:

[A、B]はインデックス、[C]-別の列

インデックスを利用するには、次のように記述します。

SELECT
    A,B,C,D,E
FROM 
    test
WHERE
   A=1
AND
   B=B
AND 
   C=3

...単一のAインデックスが利用可能な場合、デフォルトで複合インデックスを選択するのはなぜですか?

1つまたは2つの述語[A]または[A]、[B]がある場合にのみ、インデックスを使用します。[B]、[A]または[A]、[C]の順序では使用しません。追加の列[C]でインデックスを利用できるようにするには、述語を[A]、[B]、および[C]として順序付けしてインデックスを適用する必要があります。


2
正確に何を達成しB=Bますか?私はあなたが何を達成していないと思うので、私はこれがちょうどオプティマイザによって無視されていない証拠存在しないダウン投票しています
ジャック・ダグラス

2
B=B実質的に、と同じB IS NOT NULLです。上のインデックスを使用する必要はありません(a,b)
アーウィンブランドステッター
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.