4

数百万行のかなり大きなテーブルがあります。

ID (primary)
countrycode
status
flag_cc

次のSQL文を試しましたが、かなり遅かったです:

SELECT id, countrycode, status, flag_cc FROM table WHERE ID>=200000 AND countrycode=3 AND status=1 AND flag_cc=0

したがって、そのクエリを固定するためにインデックスを追加することをお勧めします。

ADD INDEX myindex(id, countrycode, status, flag_cc)

それから私は尋ねました:

EXPLAIN SELECT id, countrycode, status, flag_cc FROM table WHERE ID>=200000 AND countrycode=3 AND status=1 AND flag_cc=0

しかし、mysql は私のキーの代わりに主キーを使用したいと考えています。そこで、FORCE INDEX を使用して、主キーと自分のキーを比較しました。悲しいことに、主キーの方がはるかに高速でした。

それはどうしてですか?また、主キーが遅すぎる場合でも、そのクエリを最適化することは可能ですか?

4

1 に答える 1

3

あなたの質問は基本的に「良いインデックスとは何ですか?」です。それらについては、MySQL のドキュメント、ここでは stackoverflow を参照し、任意の検索エンジンを使用して読むことを検討してください。

大きな百科事典の索引のような索引を考えてみましょう。多くのトピックが定義されているため、インデックスを使用すると、探しているものを少し早く見つけることができます。

しかし、インデックスには何を入れるべきでしょうか? カテゴリ (科学、エンターテイメント、人物など) は? 次に、カテゴリを見つけたとき、各カテゴリに分類される記事がまだたくさんあります。合計 10,000 件の記事があり、そのうち 1000 件が科学カテゴリにあるとします。科学的なものを探している場合でも、正確な記事を探すために 1000 の記事が残っています。データベース用語では、このインデックスには適切なカーディナリティがありません。他に何も持っていなくても、実際に高速化するのに十分なほど具体的でない場合は良いことです。同じことが、開始文字によるインデックスにも当てはまります (アルファベットで 26 文字なので、インデックスを使用して、検索する記事の数を約 26 で割りますが、これもあまり具体的ではありません)。

これは、データベースでは、主キーが索引付けするのに非常に適したフィールドであることを意味します。このフィールドの 1 つの値は、データ内の 1 つの値に正確に対応するため、索引を使用して検索すると、調べる必要がなくなります。あなたはすでに特定のレコードを見つけています。

一方、true/false フラグは、データを最大 2 つのグループに分割するだけなので、インデックスを使用した後でも、十分なデータを調べることができます。

もちろん、例外もあります。たとえば、真/偽の列を持つテーブルです。通常、これは索引付けするのに不適切な列です。しかし、すべてのレコードの 0.01% のみがその列の値が「true」であり、クエリは false 値ではなく true 値を探すことがわかっている可能性があります。その場合、その true/false 列は索引付けするのに適した列です。

次に、範囲の問題があります。特定の ID を検索するのではなく、それらの範囲全体を検索しているため、ID が一意であっても、インデックスのセクション全体 (したがってデータ) が「もの」としてマークされます。インデックスを使用した後も目を通します。したがって、カーディナリティは優れていますが、この特定のクエリに使用するのに最適なインデックスではない可能性があります。

もう 1 つの問題は、インデックスの最初の列を検索していない場合、MySQL が複数列のインデックスを調べることができないことです。したがって、インデックス (ID、countrycode、status、flag_cc) は、MySQL が引き続き ID によるインデックスの使用を開始する必要があることを意味します。これはクエリでは範囲条件であり、前の段落でそれが悪い理由を説明しています。インデックスの ID 部分を適用した後でのみ、国コード部分から始めることができます。これがおそらく、別のオプションを指定したにもかかわらず、MySQL が主キー インデックスを使用しようとする理由です。

このすべての情報をテーブルに適用します。 where 句にはすべての列が含まれているため、カーディナリティが最も高く (最も異なる値)、範囲の where 句として使用されていない (そうではないID) 列から始まるインデックスを作成します。flag_ccさまざまな値がたくさん含まれている場合は、それを使用します。statusまたはcountrycodeにさらに多くの異なる値が含まれている場合は、それらのいずれかを使用します。インデックスを作成する最初の列の具体性によっては、1 つの列にインデックスを作成するだけで十分な場合があります。そうでない場合は、次善のカーディナリティを持つ列をインデックスなどに追加してみてください。

そしてもちろん、インデックス (通常、常にではありません) はルックアップを高速化しますが、更新、挿入、および削除を遅くすることを覚えておいてください!

ご覧のとおり、これは非常に単純な問題ではありません。また、私が概要を説明したことは、インデックス作成の氷山の一角にすぎないと考えてください。

ソース:
http://webmonkeyuk.wordpress.com/2010/09/27/what-makes-a-good-mysql-index-part-2-cardinality/
https://dev.mysql.com/doc/refman/ 5.6/en/multiple-column-indexes.html

于 2013-08-10T14:29:58.850 に答える