MySQLの2つの単一列インデックスと1つの2列索引?


113

次の問題に直面しましたが、何がベストプラクティスなのかわかりません。

次の表を検討してください(これは大きくなります)。

id PK | giver_id FK | recipient_id FK | 日付

私はInnoDBを使用しており、私が理解していることから、2つの外部キー列のインデックスが自動的に作成されます。ただし、次の特定の組み合わせに一致させる必要があるクエリも多数実行します。

SELECT...WHERE giver_id = x AND recipient_id = t

そのような各組み合わせは、テーブル内で一意になります。

これらの列に2列のインデックスを追加するメリットはありますか、または理論的には2つの個別のインデックスで十分/同じですか?


1
2つの列の組み合わせが一意である場合、クエリの速度を向上させるだけでなく、テーブルに一貫性を追加する一意の機能を持つ2列のインデックスを作成できます。
スグベン、

「MySQLは、インデックス内のすべての列をテストするクエリ、または最初の列、最初の2列、最初の3列などをテストするクエリに複数列インデックスを使用できます。右側の列を指定した場合インデックス定義での順序により、単一の複合インデックスは、同じテーブルで数種類のクエリを高速化できます。」- 複数列インデックス
AlikElzin-kilaka 2018

@ user1585784を推定するには、2つの列の組み合わせが一意である場合、一意のキーを使用する必要があると思います。1は、データベースレベルでの一意性を強制したい場合は実際には、一意のキーは...行くための最も簡単な方法です
Erkの

回答:


132

2つの単一列インデックスがある場合、例ではそのうちの1つだけが使用されます。

2つの列を持つインデックスがある場合、クエリは高速になる可能性があります(測定する必要があります)。2列のインデックスは、1列のインデックスとしても使用できますが、最初にリストされている列に対してのみ使用できます。

(A、B)にインデックスを付け、(B)に別のインデックスを付けると便利な場合があります。これにより、どちらか一方または両方の列を使用したクエリが高速になりますが、もちろんより多くのディスク領域も使用します。

インデックスを選択するときは、挿入、削除、更新への影響も考慮する必要があります。より多くのインデックス=遅い更新。


1
「MySQLは、インデックス内のすべての列をテストするクエリ、または最初の列、最初の2列、最初の3列などをテストするクエリに複数列インデックスを使用できます。右側の列を指定した場合インデックス定義での順序により、単一の複合インデックスは、同じテーブルで数種類のクエリを高速化できます。」- 複数列のインデックス
AlikElzin-kilaka 2018

33

次のようなカバリングインデックス:

ALTER TABLE your_table ADD INDEX (giver_id, recipient_id);

...クエリが呼ばあれば、インデックスを使用することができることを意味するgiver_id、またはの組み合わせgiver_idrecipient_id。インデックスの基準は左端に基づいてrecipient_idいることに注意してください。参照のみのクエリでは、提供したステートメントで対象となるインデックスを使用できません。

さらに、MySQLはSELECTごとに1つのインデックスのみを使用できるため、カバーするインデックスがクエリを最適化する最良の手段になります。


10
MySQL can only use one index per SELECTこれはもう当てはまりません。回答を編集して更新するとよいでしょう。
Davor、2015

カバリングインデックスを使用できない理由を説明していただけませんrecipient_idか?
Ivo Pereira、

2
MySQLの@IvoPereiraマルチカラムインデックスを使用すると、インデックス内のすべてのフィールドを左から右に使用できます。たとえば、があるINDEX (col1, col2, col3, col4)場合、インデックスはor やのWHEREような句のある検索に適用されますが、この特定のインデックスは、またはのようなものには使用されません。これらのフィールドをカバーするには、追加のインデックスを追加する必要があります。col1 = 'A'col1 = 'A' AND col2 = 'B'col1 = 'A' AND col2 ='B' AND col3 = 'C' AND col4 = 'D'WHERE col2 = 'B'WHERE col3 = 'C' AND col4 = 'D'
Slicktrick 2017

「SELECTごとに1つのインデックス」、これはmariadb 10.1にも当てはまりますか?
oldboy

1
@Anthony:いいえ。上のDavorのコメントを参照してください。
kapad

4

外部キーインデックスの1つがすでに非常に選択的である場合、データベースエンジンは指定したクエリにそのインデックスを使用する必要があります。ほとんどのデータベースエンジンは、そのような状況で最適なインデックスを選択できるように、何らかのヒューリスティックを使用します。どちらのインデックスもそれ自体では高度に選択的でない場合は、そのタイプのクエリを頻繁に使用すると言うので、両方のキーに構築されたインデックスを追加することはおそらく意味があります。

考慮すべきもう1つの点は、このテーブルのPKフィールドを削除してgiver_idrecipient_idフィールドとフィールドに主キーインデックスを定義できるかどうかです。あなたはその組み合わせがユニークであると言ったので、それはうまくいくかもしれません(あなただけが答えることができる他の多くの条件が与えられれば)。ただし、通常、追加する複雑さを追加しても、面倒なことにはなりません。


マークに感謝します。キーの1つは確かに非常に選択的であるため、問題ないはずです。私は2つの(自動)インデックスを適切な場所に保持し、それが時間の経過とともにどのように機能するかを確認することを選択しました。また、giver:recipient主キーの組み合わせについても考えましたが、各フィールドも個別に検索可能にする必要があるため、phpのオーバーヘッドが増えるだけです。また、新しいキーは(短い)整数ではなく(長い)文字列になります。
トム

2

考慮すべきもう1つの点は、両方のアプローチのパフォーマンス特性は、データセットのサイズとカーディナリティに基づくことです。2列のインデックスは、特定のデータセットサイズのしきい値で、またはまったく逆に、よりパフォーマンスが高いことに気づくだけです。正確なシナリオのパフォーマンスメトリックに代わるものはありません。


これに関するいくつかのドキュメントにリンクしてください。ありがとう。
kapad
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.