このクエリについて質問があります。
SELECT *
FROM runs
WHERE (NOW() BETWEEN began_at
AND finished_at)
begin_at列とfinished_at列の複合インデックスを作成するのは理にかなっていると思いますか?または、begined_atに対してのみインデックスを作成するのは理にかなっていますか?
あなたのスタイルは非常に珍しいです。
ほとんどの人はおそらく書くでしょうWHERE began_at < NOW() AND finished_at > NOW()
でも。両方のフィールドにインデックスを付けることをお勧めします。
組み合わせたキーは、特定の日付の組み合わせの検索を高速化するだけなので、役に立ちません。
betreeを使用する場合、結合されたキーは役に立ちますが、個別にインデックスを作成する場合ほど良くないため、これは完全には当てはまりません。等号(=)演算子を使用してフィールドの組み合わせを検索する場合は、組み合わせたキーが非常に適しています。SIngleフィールドインデックスは、ragenリクエストでより優れたパフォーマンスを発揮します。
あなたは「多次元範囲検索」のために少しグーグルすることができます。
その理由は、1つのフィールドで一致するすべてのフィールドが、基本的にbtreeのlog(n)時間で見つかるためです。したがって、全体的な実行時間はO(k * log(n))、つまりO(log(n))になります。
多次元範囲クエリには、より高いO(sqrt(n))の実行時間があります。ただし、対数ランタイムを達成するより優れた実装もあります。ただし、これらはmysqlに完全には実装されていないため、バージョンによってはさらに悪化したり、ひどいものになります。
要約すると、次のようになります。
単一フィールドでの同等性の比較:ハッシュインデックス(ランタイムO(1))
単一フィールドの範囲検索:単一フィールドのbtreeインデックス(O(log(n)))
複数のフィールドでの等式検索:結合されたハッシュキー(ランタイムO(1))
それらのケースは明らかなことです...
これはそれほど明確ではないところです。現在のバージョンでは、上記の理由により、個別にインデックスを作成する方が明らかに優れています。そのユースケースの完璧な実装により、組み合わせたキーでより良いパフォーマンスを達成できますが、それをサポートするシステムはありません。mysqlはバージョン5.0以降、ルーズインデックス(そのために必要)をサポートしていますが、非常に制限されており、クエリオプティマイザーはまれにしかインデックスを使用しません。5.3などの新しいバージョンについてはわかりません。
ただし、mysqlがルーズインデックスを実装すると、範囲要求を実行したり、さまざまな方向に並べ替えたりするフィールドにキーを組み合わせたものがますます重要になります。
等式ではなく不等式を使用しているため、複合インデックスは、2つの個別のインデックスよりも(悪くはないにしても)それほどうまく機能しません。
began_at
との両方で2つの個別のインデックスに傾倒することをお勧めしますfinished_at
。
ルーズインデックススキャンのリファレンス:
http://www.mysqlperformanceblog.com/2006/05/09/descending-indexing-and-loose-index-scan/
http://dev.mysql.com/doc/refman/5.5/en/loose-index-scan.html
「インデックスマージ」戦略は、MySQL 5以降で機能する可能性があります:http: //dev.mysql.com/doc/refman/5.0/en/index-merge-optimization.html-これは、個別のインデックスの方が優れている可能性があることも示唆しています。
しかし、私はそれを私のために機能させることができませんでした:)
この種の質問に対する正解は常に「状況によって異なります」です。両方の方法で試して、実行計画をベンチマークして比較します。テーブル内のデータ量が変化し、クエリのワークロードが変化すると、答えも変化することに注意してください。進化するシステムのインデックスは、ほとんどの場合、発火して忘れることはありません。
良い質問ですが、実際にはとの両方 began_at
のインデックスから始めますfinished_at
。このクエリを書き直す合理的な方法の1つは次のようなものだからです。
SELECT *
FROM runs
WHERE began_at < NOW()
AND finished_at > NOW()
これにより、各列に独自のインデックスが必要であることが(私には)もう少し明確になります。
この種のクエリを最適化するために、begin_at
または最適化しようとするときに、MySQLが2つの個別のインデックスを使用するようになったことがありません。finished_at
どうやら、他の人々は複合インデックスも機能しないと言っているので、MySQLにインデックスを使用してこのクエリを最適化させることは不可能かもしれません。