web-dev-qa-db-ja.com

MySQLカバーvsコンポジットvs列インデックス

次のクエリで

SELECT  col1,col2
FROM    table1
WHERE   col3='value1'
  AND   col4='value2'

col3col4に2つの別々のインデックスがある場合、このクエリで使用されるインデックスはどれですか?

クエリのテーブルごとに1つのインデックスのみが使用されていることをどこかで読みました。これは、クエリで両方のインデックスを使用する方法がないことを意味しますか?

次に、col3col4の両方を一緒に使用して複合インデックスを作成したが、[〜#〜] where [〜#〜]句でcol3のみを使用した場合パフォーマンスが悪くなりますか?例:

SELECT  col1,col2
FROM    table1
WHERE   col3='value1'

最後に、すべての場合にカバーリングインデックスを使用する方が良いですか? MYISAMとinnodbストレージエンジンの間で違いはありますか?

38
Songo

カバーリングインデックスは、複合インデックスと同じではありません。

1つはcol3に、もう1つはcol4に2つの個別のインデックスがある場合、このクエリで使用されるのはどちらですか?

カーディナリティが最も高いインデックス。
MySQLは、どのインデックスがどのプロパティを持っているかに関する統計を保持します。
(MySQLの統計で明らかなように)最も識別力のあるインデックスが使用されます。

クエリのテーブルごとに1つのインデックスのみが使用されていることをどこかで読みました。それは、クエリが両方のインデックスを使用する方法がないことを意味しますか?

副選択を使用できます。
または、col3とcol4の両方を含む複合インデックスを使用することをお勧めします。

次に、col3とcol4の両方を一緒に使用して複合インデックスを作成したが、WHERE句でcol3のみを使用した場合、パフォーマンスが低下しますか?例:

複合インデックス
正しい用語はcompoundインデックスであり、複合ではありません。
複合インデックスの左端の部分のみが使用されます。
したがって、インデックスが次のように定義されている場合

index myindex (col3, col4)  <<-- will work with your example.
index myindex (col4, col3)  <<-- will not work. 

参照: http://dev.mysql.com/doc/refman/5.0/en/multiple-column-indexes.html

左端のフィールドを選択すると、where句でインデックスのその部分を使用しなくても済むことに注意してください。
複合インデックスがあると想像してください

Myindex(col1,col2)

SELECT col1 FROM table1 WHERE col2 = 200  <<-- will use index
SELECT * FROM table1 where col2 = 200     <<-- will NOT use index.  

これが機能する理由は、最初のクエリがカバーインデックスを使用し、それをスキャンするためです。
2番目のクエリはテーブルにアクセスする必要があるため、インデックスは意味をなしませんがスキャンします。
これはInnoDBでのみ機能します。

カバーインデックスとは
カバーインデックスとは、クエリで選択されたすべてのフィールドがインデックスによってcoveredである場合を指します。その場合、InnoDB(MyISAMではない)はテーブル内のデータを読み取ることはなく、使用するだけです。インデックス内のデータにより、選択が大幅に高速化されます。
InnoDBでは、主キーがすべてのセカンダリインデックスに含まれているため、ある意味ですべてのセカンダリインデックスが複合インデックスであることに注意してください。
これは、InnoDBで次のクエリを実行した場合を意味します。

SELECT indexed_field FROM table1 WHERE pk = something

MySQLは常にカバーインデックスを使用し、実際のテーブルにはアクセスしません。

私は ヨハンの答え 完全性のために賛成しましたが、セカンダリインデックスに関して彼が行う次のステートメントは正しくないおよび/または混乱していると思います。

Note that in InnoDB the primary key is included in all secondary indexes, 
so in a way all secondary indexes are compound indexes.

This means that if you run the following query on InnoDB:

SELECT indexed_field FROM table1 WHERE pk = something

MySQL will always use a covering index and will not access the actual table.

主キーがセカンダリインデックスに[〜#〜]含まれている[〜#〜]であることに同意しますが、MySQLに同意しません "ここで指定されたSELECTクエリでは、常にカバーインデックス "が使用されます。

この場合、理由を確認するために、完全なインデックス「スキャン」が常に必要であることに注意してください。これは「シーク」操作と同じではありませんが、代わりにセカンダリインデックスの内容を100%スキャンします。これは、セカンダリインデックスがプライマリキーによって順序付けられていないという事実によるものです。 「indexed_field」で並べ替えられます(そうでない場合、インデックスとしてはあまり使用されません!)。

この後者の事実に照らして、主キーを「シーク」してから、セカンダリインデックスからではなく、「実際のテーブルから」indexed_fieldを抽出する方が効率的な場合があります。

5
Sam T

これは私がよく耳にする質問であり、次の理由で問題について多くの混乱があります。

  • 長年にわたるmySQLの違い。インデックスと複数のインデックスのサポートは、何年にもわたって変更されました(サポートされる方向に)

  • innoDB/myISAMの違いいくつかの重要な違い(以下)がありますが、複数のインデックスがそれらの1つであるとは思いません

MyISAMは古いですが、実績があります。 MyISAMテーブルのデータは、次の3つの異なるファイルに分割されます。-テーブル形式、データ、およびインデックス。
InnoDBはMyISAMよりも比較的新しく、トランザクションに対して安全です。 InnoDBは、マルチユーザーの同時実行性とパフォーマンスを向上させるテーブルロックとは対照的に、行ロックも提供します。 InnoDBには外部キー制約もあります。
行ロック機能があるため、InnoDBは高負荷環境に最適です。

確実に行うには、必ずexplain_planを使用してクエリの実行を分析してください。

1
Michael Durrant