複数列のインデックスとパフォーマンス


31

複数列のインデックスを持つテーブルがあり、クエリのパフォーマンスを最大にするためのインデックスの適切な並べ替えについて疑問があります。

シナリオ:

  • PostgreSQL 8.4、約100万行のテーブル

  • c1の値には、約100の異なる値を指定できます。値は均等に分布していると想定できるため、可能な値ごとに約10000行あります。

  • c2に1000個の異なる値を指定できます。可能な値ごとに1000行あります。

データを検索するとき、条件には常にこれら2つの列の値が含まれるため、テーブルにはc1とc2を組み合わせた複数列のインデックスがあります。フィルタリングに1列のみを使用するクエリがある場合、複数列インデックスのを適切に順序付けることの重要性について読みました。これは、このシナリオには当てはまりません。

私の質問はこれです:

フィルターの1つが非常に小さなデータセットを選択するという事実を考えると、最初のインデックスが最も選択的なインデックス(より小さなセットを許可するインデックス)である場合、パフォーマンスを改善できますか?参照記事のグラフィックを見るまで、この質問を考えたことはありませんでした。

ここに画像の説明を入力してください

複数列インデックスについての参照記事から抜粋した画像。

クエリは、フィルタリングに2つの列の値を使用します。フィルタリングに1列のみを使用するクエリはありません。それらはすべて次のとおりWHERE c1=@ParameterA AND c2=@ParameterBです。次のような条件もあります。WHERE c1 = "abc" AND c2 LIKE "ab%"

回答:


36

回答

Webサイトを参照してuse-the-index-luke.comいるため、次の章を検討してください。

インデックスの使用、ルーク› Where句›範囲の検索› Greater、Less、BETWEEN

あなたの状況に完全に一致する例があります(2列のインデックス、1つは同等性、もう1つはrangeについてテストされています)、@ ypercubeのアドバイスが正確である理由を説明します(これらの素敵なインデックスグラフィックをさらに使用):

Rule of thumb: index for equality first  then for ranges.

1列だけでも良いですか?

1列のみのクエリに対して何をすべきかは明らかです。これらの関連する質問の下でそれに関する詳細とベンチマーク:

最初に選択性の低い列ですか?

それとは別に、両方の列に等しい条件しかない場合はどうでしょうか?

どうでもいい。実際に重要な独自の条件を受け取る可能性が高い列を最初に配置します。

このデモを検討するか、自分で再現してください。10万行の2列の単純なテーブルを作成します。1つは非常に少数で、もう1つは多くの異なる値を持ちます

CREATE TEMP TABLE t AS
SELECT (random() * 10000)::int AS lots
     , (random() * 4)::int     AS few
FROM generate_series (1, 100000);

DELETE FROM t WHERE random() > 0.9;  -- create some dead tuples, more "real-life"

ANALYZE t;

SELECT count(distinct lots)   -- 9999
     , count(distinct few)    --    5
FROM   t;

クエリ:

SELECT *
FROM   t
WHERE  lots = 2345
AND    few = 2;

EXPLAIN ANALYZE 出力(キャッシュ効果を除外するためのベスト10):

tのSeqスキャン(コスト= 0.00..5840.84行= 2幅= 8)
               (実際の時間= 5.646..15.535行= 2ループ= 1)
  フィルター:((lots = 2345)AND(few = 2))
  バッファー:ローカルヒット= 443
合計ランタイム:15.557ミリ秒

インデックスを追加して、再テストします。

CREATE INDEX t_lf_idx ON t(lots, few);
tでt_lf_idxを使用したインデックススキャン(コスト= 0.00..3.76行= 2幅= 8)
                                (実際の時間= 0.008..0.011行= 2ループ= 1)
  インデックス条件:((lots = 2345)AND(few = 2))
  バッファー:ローカルヒット= 4
合計ランタイム:0.027 ms

他のインデックスを追加して、再テストします。

DROP INDEX t_lf_idx;
CREATE INDEX t_fl_idx  ON t(few, lots);
tでt_fl_idxを使用したインデックススキャン(コスト= 0.00..3.74行= 2幅= 8)
                                (実際の時間= 0.007..0.011行= 2ループ= 1)
  インデックス条件:((few = 2)AND(lots = 2345))
  バッファー:ローカルヒット= 4
合計ランタイム:0.027 ms

これは、インデックス内の3(またはそれ以上)列にも当てはまりますか?
ハイド

@hayd:「これ」が何を指しているのかわかりません。新しい質問をするかもしれません。コンテキストのためにいつでもこれを参照できます。(リンクを戻すためにここにコメントをドロップしてください。)
Erwin Brandstetter

「これ」とは、「インデックス定義に3つ以上の列がある場合、インデックス定義の順序付けを行う」ことを意味します
hayd

@hayd:最も重要な点:btreeインデックスは、主要なインデックス式に等しい条件があるクエリに適しています。それらの間の順序はほとんど無関係です。コメントに収まらない他の多くの詳細...
Erwin Brandstetter

おかげで、首尾一貫した質問を書いて、それにリンクしてみます。
ハイド

11

あなたが言うように、これら2つの列を含むクエリが両方の列のすべての等価性チェックである場合、例えば:

WHERE c1=@ParameterA AND c2=@ParameterB

これを気にしないでください。違いがあるとは思いませんし、違いがあったとしても、それは無視できるでしょう。もちろん、データとサーバー設定でいつでもテストできます。DBMSのバージョンが異なると、最適化に関して若干異なる動作をする場合があります。

インデックス内の順序は、1つの列のみのチェック、不等式条件、1つの列の条件と他の列のグループ化など、他のタイプのクエリにとって重要です。

2つの注文のいずれかを選択する場合、選択性の低い列を最初に配置することを選択します。列yearとを持つテーブルを考えてみましょうmonthWHERE year = 2000条件またはa WHERE year BETWEEN 2000 AND 2013またはa が必要になる可能性が高くなりますWHERE (year, month) BETWEEN (1999, 6) AND (2000, 5)

このタイプのクエリはWHERE month = 7 GROUP BY year確実に必要になる場合があります(7月に生まれた人を探す)が、それほど頻繁ではありません。もちろん、テーブルに保存されている実際のデータに依存します。今のところ1つの順序を選択し、言って(c1, c2)ください(c2, c1)。後で別のインデックスをいつでも追加できます。


OPのコメントの後に更新します

次のような条件もあります。 WHERE c1 = 'abc' AND c2 LIKE 'ab%'

このタイプのクエリは、c2列の範囲条件と正確に一致する場合に(c1, c2)インデックスが必要になります。逆タイプのクエリもある場合:

WHERE c2 = 'abc' AND c1 LIKE 'ab%'

(c2, c1)インデックスもあればいいでしょう。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.