18

結合のためにフィールドを頻繁に使用することがわかっている場合は、そのフィールドにインデックスを作成することをお勧めします。

私は一般的に、表の索引付けの概念を理解しています (紙の本の索引を使用すると、ページごとに検索しなくても特定の用語を検索できるようになります)。しかし、いつそれらを使用するかについてはあまり明確ではありません。

USERS、COMMENTS、および VOTES テーブルの 3 つのテーブルがあるとします。そして、クエリがコメントとそれらのコメントに対する上/下の投票数を返す、Stackoverflow のようなコメント スレッドを作成したいと考えています。

USERS table
user_id user_name   
 1         tim
 2         sue
 3         bill 
 4         karen
 5         ed

COMMENTS table
comment_id topic_id    comment   commenter_id
 1            1       good job!         1
 2            2       nice work         2
 3            1       bad job :)        3

VOTES table
 vote_id    vote  comment_id  voter_id
  1          -1       1          5
  2           1       1          4
  3           1       3          1
  4          -1       2          5
  5           1       2          4

topic_id=1 の投票を返すクエリと SQLFiddle は次のとおりです。

select u.user_id, u.user_name,
   c.comment_id, c.topic_id, c.comment,
   count(v.vote) as totals, sum(v.vote > 0) as yes, sum(v.vote < 0) as no,
   my_votes.vote as did_i_vote
from comments c
join users u on u.user_id = c.commenter_id
left join votes v on v.comment_id = c.comment_id
left join votes my_votes on my_votes.comment_id = c.comment_id
and my_votes.voter_id = 1
where c.topic_id = 1
group by c.comment_id, u.user_name, c.comment_id, c.topic_id, did_i_vote;

コメントと投票の数が数百万になると仮定しましょう。クエリを高速化するために、私の質問は、にインデックスを配置する必要があるcomments.commenter_idvotes.voter_idどうvotes.comment_idかです。

4

2 に答える 2

27

SQL テーブルのどこでインデックスを使用するかは、常に明確であるとは限りません。ただし、ほとんどの場合、決定に役立つ一般的な経験則がいくつかあります。

  1. where 句で使用されている列にインデックスを付ける
  2. 結合に使用する列にインデックスを配置します。
  3. 同じテーブル内の列に 4 ~ 5 個を超えるインデックスを使用しないようにしてください。

覚えておくべき一般的な概念は次のとおりです。

  1. 使用するインデックスは、それらの列の検索を高速化します。
  2. 追加したインデックスにより、このテーブルへの挿入が少し遅くなります。
  3. 前の2つから。インデックスを使用するかどうか、およびどの列で使用するかどうかを決定するために、テーブルに対して行う挿入とクエリの数を決定するのは、ユーザーの責任です。

編集

@AndrewLazarus コメントは非常に重要であり、回答に追加することにしました。

  1. 異なる値がほとんどない列にはインデックスを使用しないでください。たとえば、状態がほとんどない場合に状態を保持する列、またはブール値です。そうしない理由は、インデックスは値の数で除算されるだけであるため、実際には役に立たないためです。また、それらの数が少ないため、実際のメリットはありません。テーブルはインデックスでより多くのスペースを消費し、挿入時にプリフォームが遅くなりますが、クエリ中のパフォーマンスが大幅に向上することはありません
于 2012-11-18T15:27:28.200 に答える
6

これは、使用されるいくつかのキーの更新ですhttp://www.sqlfiddle.com/#!2/94daa/1

エンジンは、インデックスを使用するコストと使用しないコストを比較する必要があります。インデックスを使用するには、さらに行を追加する必要があることに気付くでしょう。

インデックスを使用すると、エンジンはインデックスを使用して一致する値を取得する必要がありますが、これは高速です。次に、一致を使用してテーブル内の実際の行を検索する必要があります。インデックスが行数を絞り込まない場合は、テーブル内のすべての行を検索する方が高速な場合があります。

mysql に SQL Server のクラスター化インデックスに似たものがあるかどうかはわかりません。この場合、インデックスとテーブル データは同じ構造にあるため、インデックス ルックアップの 2 番目のステップはありません。

2 つの異なる方法でインデックスを導入しました。1 つ目は、主キーを定義することにより、users テーブルにインデックスを導入しました。これにより、user_id 列に一意のインデックスが暗黙的に作成されます。一意のインデックスとは、同じ値のセットを 2 回挿入できない場合を意味します。単一列インデックスの場合、これは、同じ値を 2 回持つことができないことを意味します。

ページごとに 1 人のユーザーがいるテーブルのユーザーの本を想像すると、作成されたインデックスは、user_id の並べ替えられたリストを提供し、それぞれがユーザーのページ番号を持ちます。リストは通常​​、特定の番号をすばやく検索できるように、ある種のツリー形式で保存されます。電話帳で名前を検索する方法を考えてみてください。名前が見つかるまですべてのページをスキャンするだけでなく、名前がどこにあるかを推測し、近くに到達するまでページのチャンクを前後にスキップします。 . 通常、O(log 2 n) 時間でインデックス内の値を検索できます。ここで、n は行数であり、同様の数のインデックス ページを読み取る必要があります。

DB エンジンに query が与えられた場合、select * from users Where user_id = 32 つの選択肢があります。各データ ページを読み取り、適切な値を探すことができます (主キーがあるという事実を使用して、最初に停止する場合があります)。もう 1 つの方法は、インデックスを読み取って正しいデータ ページを取得してから、データ ページを検索することです。

具体的かつ単純にするために、テーブルに 1024 のエントリがあると仮定します。各エントリが 1 つのデータ ページを使用すると仮定します。インデックス ツリーの各エントリが 1 つのインデックス ページを使用するとします。インデックスはバランスがとれていると仮定すると、インデックスには 10 のレベルがあり、合計 2047 ページになります。(これらの仮定はすべて疑わしいですが、すべての列を一度にインデックス化する傾向がないため、特にインデックス ページはほとんど常にデータ ページよりも小さくなります)。

テーブル スキャン アプローチを実行するには、1024 データ ページを読み取る必要があります。インデックスを使用するには、10 のインデックス ページと 1 つのデータ ページを読み取る必要があります。ほとんどすべてのデータベースのパフォーマンスは、読み取られるページの量を最小限に抑えることに関係しています。

複数列のインデックスを使用すると、一連のデータをすばやく検索できます。(col1, col2) のインデックスがある場合、col1 でのマッチングだけでも改善されます。

このcreate indexステートメントは、インデックスが作成された列と、重複する値が許可されているかどうかを示しているだけです。

本の類推を再び使用するCreate Index ix_comment_id on votes (comment_id, voter_id)と、対応するデータ行への参照を使用して、comment_id、voter_id の順序付きリストが作成されます。

+------------+--------------+---------+
| comment_id | reference_id | row_ref |
+------------+--------------+---------+
|          1 |            4 |    ref1 |
|          1 |            5 |    ref2 |
|          2 |            4 |    ref3 |
|          2 |            5 |    ref4 |
|          3 |            1 |    ref5 |
+------------+--------------+---------+
于 2012-11-18T15:24:47.660 に答える