web-dev-qa-db-ja.com

カーディナリティの低い列インデックスとSELECT

長い(たとえば1000000エントリ)MySQLテーブルtに、10未満の異なるTINYINT値を持つ列cがあるとします。

また、これらの値のほとんど(99%または99.9%など)がゼロに等しいと仮定します。

この列にインデックスを追加すると、次のようなクエリが高速になりますか?

SELECT * FROM t WHERE c > 1
1
porton

答えは「依存する、あなたは十分な情報を提供しなかった」です。

オプティマイザの立場に身を置く。 SELECT *を実行するこのクエリが表示されます。 Cがテーブルの唯一の列ではない可能性が高いです。たとえば、列AとBの両方があるとします。つまり、Cのインデックスシークでは、テーブルからAとBを戻すために、各行の検索操作が必要になります。これはコストに帰着します-100万行ある場合、オプティマイザがクエリが1%= 10,000行を返すことを認識できる場合。つまり、インデックスを使用するコストは、インデックスシークを実行して10K行を取得し、次に10Kルックアップを実行して列AとBを戻すことです。

残念ながら、MySQLは他のいくつかのエンジンのようなヒストグラムを維持せず、密度ベクトルのみを維持します...したがって、行の約10%が返されると推定される場合があり、その情報を使用すると、推定コストははるかに高くなります。

代わりに、100万行をスキャンし、インデックスを使用せずに「オンザフライ」でフィルタリングします。どちらが安いですか?わかりません。テーブルのサイズによって異なります。 AとBの両方がスペースをほとんどとらないブール列である場合、テーブルをスキャンする方が安価であると考えられる場合があります。 AとBが巨大なBLOBである場合、推定コストが増加する可能性があります。

ところで、*を使用する代わりに(これは例として示しただけだと思います)、必要な列の最小セットのみをリストします。たとえば、AとCをリストすると、(C、A)の複合インデックスはルックアップを自分で保存したので、常に最も安い選択肢になります。

HTH

4
SQLRaptor