web-dev-qa-db-ja.com

複数列のインデックスは単一列の選択にも機能しますか?

(たとえば)インデックスを持っています。

CREATE INDEX someIndex ON orders (customer, date);

このインデックスはcustomer and dateが使用されているクエリのみを高速化しますか、それともこのような単一列のクエリを高速化しますか?

SELECT * FROM orders WHERE customer > 33;

SQLiteを使用しています。


答えが「はい」の場合、なぜテーブルごとに複数のインデックスを作成できるのですか?


さらに別の質問:クエリで両方の列を使用する場合、結合インデックスは2つの分離インデックスと比べてどのくらい高速ですか?

44
Georg Schölly

marc_sが最初の質問に対する正しい答えを持っています。マルチキーインデックスの最初のキーは、シングルキーインデックスと同じように機能しますが、後続のキーは機能しません。

複合インデックスの速度はデータとインデックスとクエリの構造に依存しますが、通常は重要です。インデックスを使用すると、Sqliteでフィールドをバイナリ検索できます。

クエリを実行した場合の例を使用すると、次のようになります。

SELECT * from orders where customer > 33 && date > 99

Sqliteはまず、顧客> 33のテーブル全体でバイナリ検索を使用してすべての結果を取得します。次に、日付> 99を検索する結果のみでバイナリ検索を実行します。

Customerとdateに2つの別個のインデックスを使用して同じクエリを実行した場合、Sqliteはテーブル全体を2回バイナリ検索する必要があります。

したがって、速度がどの程度向上するかは、クエリに関してインデックスをどのように構造化するかによって異なります。理想的には、インデックスとクエリの最初のフィールドは、2番目の検索で実行する作業量を大幅に削減することで最大の速度向上を実現できるため、一致を可能な限り排除するフィールドである必要があります。

詳細については、これを参照してください: http://www.sqlite.org/optoverview.html

38
Jared Miller

私はこれがうまくいくと確信しています、はい-それはとにかくMS SQL Serverでうまくいきます。

ただし、日付のみで選択する必要がある場合、このインデックスは役に立ちません。日付範囲。その場合、クエリをより効率的にするために、日付だけに2番目のインデックスを作成する必要がある場合があります。

マーク

6
marc_s

私は通常、複合インデックスを使用して、ページ分割または「ストリームリーに」要求するデータを並べ替えます。

顧客が複数の注文を行うことができると仮定します。顧客0〜11が存在し、顧客ごとにいくつかの注文がランダムな順序で挿入されています。顧客番号と日付の順にクエリを並べ替えたいのですが。顧客が複数の同一の日付を持っている場合は、idフィールドも最後に分割セットにソートする必要があります(それが決して起こらない場合でも)。

sqlite> CREATE INDEX customer_asc_date_asc_index_asc ON orders
          (customer ASC, date ASC, id ASC);

ソートされたクエリのページ1を取得します(10アイテムに制限されています):

sqlite> SELECT id, customer, date FROM orders
          ORDER BY customer ASC, date ASC, id ASC LIMIT 10;

2653|1|1303828585
2520|1|1303828713
2583|1|1303829785
1828|1|1303830446
1756|1|1303830540
1761|1|1303831506
2442|1|1303831705
2523|1|1303833761
2160|1|1303835195
2645|1|1303837524

次のページを取得します。

sqlite> SELECT id, customer, date FROM orders WHERE
          (customer = 1 AND date = 1303837524 and id > 2645) OR
          (customer = 1 AND date > 1303837524) OR
          (customer > 1)
          ORDER BY customer ASC, date ASC, id ASC LIMIT 10;

2515|1|1303837914
2370|1|1303839573
1898|1|1303840317
1546|1|1303842312
1889|1|1303843243
2439|1|1303843699
2167|1|1303849376
1544|1|1303850494
2247|1|1303850869
2108|1|1303853285

等々...

インデックスを配置すると、LIMITと組み合わせたクエリOFFSETを使用する場合にサーバー側のインデックススキャンが削減されます。クエリ時間が長くなり、オフセットが大きくなるほど、ドライブはより強くシークします。この方法を使用すると、それを排除できます。

後でデータを結合する予定で、リクエストごとに限られたデータセットのみが必要な場合は、この方法を使用することをお勧めします。上記のようにSUBSELECTに対して結合して、大きなテーブルのメモリオーバーヘッドを削減します。

3
whardier