私は主にActionscript開発者であり、SQLの専門家ではありませんが、単純なサーバー側のものを開発する必要がある場合があります。なので、タイトルの質問はもっと経験豊富な人に聞いてみようと思いました。
私の理解では、いくつかの異なる値を保持する列にインデックスを設定しても、あまり利益は得られません。ブール値を保持する列があり(実際には小さなintですが、フラグとして使用しています)、この列は、ほとんどのクエリのWHERE句で使用されています。理論上の「平均」の場合、レコードの値の半分は1で、残りの半分は0です。したがって、このシナリオでは、データベースエンジンは全表スキャンを回避できますが、とにかく多くの行を読み取る必要があります。 (合計行数/ 2)。
では、この列をインデックスにする必要がありますか?
記録のために、私はMysql 5を使用していますが、カーディナリティが低いことがわかっている列にインデックスを付けることが意味がある/意味がない理由についての一般的な理論的根拠にもっと興味があります。
前もって感謝します。
次の場合、インデックスはカーディナリティの低いフィールドでも役立ちます。
可能な値の1つが他の値と比較して非常にまれであり、それを検索する場合。
たとえば、色覚異常の女性は非常に少ないため、次のクエリを実行します。
SELECT *
FROM color_blind_people
WHERE gender = 'F'
おそらくgender
のインデックスから恩恵を受けるでしょう。
値がテーブル順にグループ化される傾向がある場合:
SELECT *
FROM records_from_2008
WHERE year = 2010
LIMIT 1
ここには3
の異なる年しかありませんが、おそらく最初に古い年のレコードが追加されるため、インデックスがない場合は、最初の2010
レコードを返す前に非常に多くのレコードをスキャンする必要があります。
ORDER BY / LIMIT
が必要な場合:
SELECT *
FROM people
ORDER BY
gender, id
LIMIT 1
インデックスがないと、filesort
が必要になります。 LIMIT
に対していくらか最適化されていますが、それでも全表スキャンが必要です。
インデックスがクエリで使用されるすべてのフィールドをカバーする場合:
CREATE INDEX (low_cardinality_record, value)
SELECT SUM(value)
FROM mytable
WHERE low_cardinality_record = 3
DISTINCT
が必要な場合:
SELECT DISTINCT color
FROM tshirts
MySQL
はINDEX FOR GROUP-BY
を使用します。色が少ない場合、このクエリは数百万のレコードがあっても即座に実行されます。
これは、カーディナリティの低いフィールドのインデックスがカーディナリティの高いフィールドのインデックスよりもmore効率的であるシナリオの例です。
DML
のパフォーマンスがそれほど問題にならない場合は、インデックスを作成しても安全であることに注意してください。
オプティマイザーがインデックスが非効率的であると判断した場合、インデックスは使用されません。
複合インデックスにブールフィールドを含めることは価値があるかもしれません。たとえば、通常は日付順に並べ替える必要があるメッセージの大きなテーブルがあるが、ブール値Deletedフィールドもある場合は、次のようにクエリを実行することがよくあります。
SELECT ... FROM Messages WHERE Deleted = 0 AND Date BETWEEN @start AND @end
削除済みフィールドと日付フィールドに複合インデックスを設定すると、間違いなくメリットがあります。
私は通常、単純な「インデックスあり」と「ない」インデックステストを行います。私の経験では、インデックス付き列でORDERBYを使用するクエリでほとんどのパフォーマンスが得られます。その列に並べ替えがある場合は、インデックス作成が役立つ可能性があります。
レコードの値の半分が1になり、残りの半分が0になる場合、その列にインデックスを付ける意味はありません。クエリオプティマイザはそれを利用しない可能性があります。
ただし、通常は、「アクティブ」レコードの小さなセットと「非アクティブ」のセットがますます大きくなります。たとえば、バグ追跡システムでは、アクティブなバグに関心があり、完成してアーカイブされたバグをすべて見ることはほとんどありません。このような場合の秘訣は、レコードが非アクティブ化/削除されたときのタイムスタンプを格納する「dateInactivate」列を使用することです。名前が示すように、レコードがアクティブな間は値はNULLですが、非アクティブ化されたら、システムの日時に書き込みます。したがって、各レコードには一意の(厳密には言えない)値があるため、「削除された」レコードの数が増えると、その列のインデックスの選択性が高くなります。クエリには
"... AND dateInactivated is NULL ..."
述語の一部として、インデックスはあなたが気にかけている行のちょうどいいセットを引き込みます。
私見それは限られた有用性です。ほとんどの場合、フラグに加えて、クエリで使用している他の基準があり、おそらくもっと役立つと思います。
50%の場合、ベンチマークの有無にかかわらずベンチマークを実行し、それが大きな違いを生むかどうかを確認します。