2010-12-15 9 views
4

私は非常に大きなテーブル(〜1.7M行)の最適化問題を抱えています。数値カラムのMySQLインデックスはクエリを遅くします

行を選択するときに2つの列が使用されます。それらをcolAとcolBとします。彼らは、 '二重'(小数点以下5桁)タイプの両方範囲であるから:

で、colA:-90〜90 COLB:インデックスなし-180〜180

、フォームの任意のクエリ:

SELECT * FROM table where colA BETWEEEN a and b AND colB BETWEEN c and d 

は、(a、b)、(c、d)の範囲にかかわらず(MySQLはすべての行を調べなければならないため)ほぼ同じ時間(〜1秒)かかります。

私は2つのことが起こる、コーラとCOLBにインデックスを追加する場合:クエリ(a、b)は&(C、D)の範囲には、例えば、小さい:

SELECT * FROM table where colA BETWEEEN -4 and 4 AND colB BETWEEN 3 and 7 

実行非常に迅速に(約1/10秒)。ただし、照会された値の範囲で実行時間が長くなります。たとえば:

SELECT * FROM table where colA BETWEEEN -80 and 80 AND colB BETWEEN -150 and 150 

は、実行する分程度かかります。

私はB-treeが文字列としてどのように機能するのか知っていますが、データが数値で、範囲を使ってクエリが実行されているときは、メカニズムがわかりません。

誰でもこのクエリを最適化する方法を提案できたら、私は感謝します。 1つの考えは、小さな範囲にインデックスを使用し、大きなものに対しては使用しないようMySQLに指示することですが、これを可能にするコマンドを見つけることができませんでした。

おかげ

編集:私は愚かな言及を忘れてしまった何かがあり

説明しています。結果はrand()によって整理されます - これは非効率的であることを認識していますが、テーブルからランダムに限られた数の行を取得する方法は他にありません。

rand()を追加しても、インデックスがない場合の実行時間には影響しませんが、存在する時間を大幅に短縮します。

EDIT2:これは複合インデックスを使用しています。

小さな範囲:

9783行

"RAND(BY -10と5 ORDERの間に35と38とCOLB間コーラ)20を制限する場合、テーブルSELECT * FROM説明" (速い)INDEX WITH

+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra  | 
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+ 
| 1 | SIMPLE  | table | ALL | NULL   | NULL | NULL | NULL | 1673784 | Using where | 
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+ 

(非常に速い)NO INDEXない

+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra  | 
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+ 
| 1 | SIMPLE  | table | range | test   | test | 18  | NULL | 136222 | Using where | 
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+ 



広い範囲:

"セレクト説明* -80と80とRAND BY COLB ORDER -150〜150の間のコーラ()20を制限テーブルから、"

1631862行

NO INDEX(速い)INDEX(非常に遅い:> 60秒)WITH

+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra  | 
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+ 
| 1 | SIMPLE  | table | ALL | NULL   | NULL | NULL | NULL | 1673784 | Using where | 
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+ 

:要約する

​​3210

EDIT3: (すべてのクエリが20行を返すように制限されています)

指標とランドとの大きな範囲():45秒
大きな範囲ランド無し()は、インデックス付き:0.003秒

大きなランドとの範囲、無度:1秒
大きい範囲せずにrand、インデックスなし:0.003秒

異常は次のとおりです。「インデックス付きの大きな範囲()、45秒」。

+0

を無効にするインデックスをしてください強制することができます。 2番目のケースではインデックスが使用されていないこともわかります – zerkms

+0

"colAとcolBにインデックスを追加すると" ---これを明確にしてください。あなたが私たちに示したクエリについては、最も効率的なのは2 **の分離した**インデックスを作成することです。 1つは「ColA」、もう1つは「ColB」です。 – zerkms

+0

@zerkms:2つの分離されたインデックスがコンポジットインデックスより効率的なのはなぜですか?表示されたクエリでは、両方の列がwhere句にANDと組み合わされていますが、これは複合インデックスの完璧なシナリオのようです。 – Thilo

答えて

5

私はB-木は文字列に対してどのように動作するかを知っているが、データが数値で、クエリは、範囲を使用して行われたとき、私はメカニズムのかわかりません。

数字の場合と同じように、文字列と同じように動作します。クエリを実行するほぼ同じ時間がかかるインデックスなし

(約1秒)にかかわらず、範囲(A、B)、および(C、D)

の実行時の全表スキャンはWHERE条件の内容によって大きく変化しません。索引アクセス・パスの所要時間は、戻される行数に比例します。クエリがテーブルの重要な部分を選択した場合、インデックスを使用すると、インデックスを使用しない場合よりも常に遅くなります。

インデックスのアクセス権は、インデックスの選択性が十分である場合、つまり取得される行の数が少ない場合(ほとんどの場合は10%と言います)にのみ有効です。実行時間は返される行の数にほぼ比例し、完全な表スキャンよりも遅くなる可能性があります。

小さな範囲にはインデックスを使用し、大きなものには使用しないようMySQLに指示しますが、これを許可するコマンドは見つかりませんでした。

クエリオプティマイザは、インデックスを使用するかどうかを決定するために統計とヒューリスティックスを使用する必要があります。おそらく、OPTIMIZE TABLEを使用してこれらの統計情報を更新する必要があります。それでもまだ適切な決定が下されない場合は、hintsで手伝ってください。

SELECT * FROM table 
    IGNORE INDEX (the_index) 
    where colA BETWEEEN -80 and 80 AND colB BETWEEN -150 and 150 

その他のオプションは、場合にのみ、また、(数を(あなたはそれからどんな利益を見たことがない場合は、定数1秒の応答時間が十分であるかもしれない)インデックスを削除、またはその両方のカラムに複合インデックスをしようとすることができクエリの結果であるレコードの数が少ない)。多くの結果に45秒

ネストされたループ+ SORT:インデックスとランドとの

大きな範囲():


今、あなたはLIMIT 20に言及していること、それはより多くの意味を作る開始します

インデックスから(範囲内の)すべてのレコードを取得し、テーブルから1つずつ取り出して並べ替え、次に20に制限します。

インデックス付きのrand()なし

大きな範囲、:0.003秒

ネストされたループは、インデックスから20件のレコードを取得し、テーブルから一つずつをフェッチ20を記録

で中止され、それを返す。実際には大きな並べ替えはありません。

ランドと

大きな範囲、何の指標:1秒

全表スキャン+テーブル全体を通して読むSORT

は、範囲内で、その後、並べ替え、その後、20に制限されているものに保つませんランドなし

大きな範囲、なしインデックス:0.003秒

フルテーブルスキャン、20レコードで中断

テーブルを読み始め、範囲内にあるものを保存し、20時に停止して戻る。

+0

OPが私たちに 'EXPLAINS'を表示する前に、私は奇妙な(はい、この習慣はひどい)' IGNORE INDEX'についてのアドバイスを避けることを好む。そして、私たちはmysqlがすでにインデックス自体を無視していることを説明します。 – zerkms

+2

最初にEXPLAINSを調べることに同意します。しかし、クエリがインデックスを作成する前よりずっと遅い場合、mysqlはおそらくインデックスを無視していないでしょう... – Thilo

+0

@Thilo:前に 'a'と' b'の値が分かっていませんそれを言わなかった。 – zerkms

0

多くの複製があるインデックスは無駄です。

インデックスで両方のフィールドが使用されていることを確認してください。 COLBため

create index idx_faster on tbl_mytbl (colA,colB) 

あなたは最終クエリが最初よりも長いを取るべきではない、

create index idx_colb on tbl_mytbl (colB) 

について、 /トン

0

を別のものを追加することができます。 MySQLはインデックスを更新していない可能性がありますOPTIMIZE TABLE

EXPLAINEXPLAIN ANALYZEでクエリを計画する方法を確認することもできます。

最後に、あなたは `両方のクエリのEXPLAIN`を入れIGNORE INDEX (idx_name)

関連する問題