4

次のようなテーブルがあります。

ID    StartRange    EndRange
----------------------------
 1        1            3
 2        4            8
 3        9           12

などなど、500 万件を超えるレコードが存在します。最後のレコードは次のようになります。

ID        StartRange    EndRange
---------------------------------
5235976   9894727374   9894727378

つまり、各レコードでStartRangeandが重複することはありません。EndRange

範囲に一致する数値の対応する ID を見つけるクエリを実行する必要があります。

SELECT ID FROM BigTable WHERE '5000000' BETWEEN StartRange AND EndRange;

残念ながら、このクエリは完了するまでに数秒かかります。実行時間が最小限になるように最適化する必要があります。少し調査したところ、インデックスを追加しても役に立たないようです。数値が正確にStartRangeまたはEndRange値である場合にのみ適用され、その間にある場合は適用されないためです。

実行時間を短縮するために使用できるヒントやコツはありますか? できれば1秒以内が理想です。

4

4 に答える 4

5

私はIPアドレス範囲の表で同様の問題を抱えていましたが、以下は本当にうまくいきました。少なくとも StartRange にはインデックスが必要です。

SELECT ID
FROM BigTable
INNER JOIN
  (SELECT MAX(StartRange) AS start
   FROM BigTable
   WHERE StartRange <= @Target) AS s
ON StartRange = s.start
WHERE EndRange >= @Target;
于 2012-10-03T00:05:53.393 に答える
3

テーブルに複合インデックスを追加します。このインデックスは、StartRangeおよびEndRangeフィールドで作成する必要があります。

ALTER TABLE `BigTable` ADD INDEX ( `StartRange` , `EndRange` );

次にEXPLAIN、クエリで使用して、新しいインデックスが使用されていることを確認します。

EXPLAIN SELECT ID FROM BigTable WHERE '5000000' BETWEEN StartRange AND EndRange;

出力は、MySQLがこのクエリで新しいインデックスを使用できないことを示しています。次に、最初のクエリを書き直すことができます。

SELECT ID FROM BigTable WHERE StartRange>='5000000' AND EndRange<='5000000'
                            OR EndRange>='5000000' AND StartRange<='5000000'

この新しいクエリは、最初のクエリと同じ結果を返します。良いニュースは次のEXPLAINとおりです。

EXPLAIN SELECT ID FROM BigTable WHERE StartRange>='5000000' AND EndRange<='5000000'
                            OR EndRange>='5000000' AND StartRange<='5000000'

出力は、MySQLが新しいインデックスを使用できることを示しています。

于 2012-10-03T00:07:57.573 に答える
2

値が と に一致しない場合でも、インデックスはこのクエリを適切に処理する必要がStartRangeありEndRangeます。

于 2012-10-02T23:58:42.827 に答える
1

インデックスはこのクエリを高速化しません。インデックスは BETWEEN 検索に使用できますが、"正しい方法" である場合にのみ使用できます (例: StartRange BETWEEN 10000 AND 20000)。

このクエリを高速化するには、いくつかのトリックに頼る必要があります。

まず、範囲テーブルが静的であるか急速に拡大せず、範囲値が実際に整数である場合、最低の StartRange から最高の EndRange までのすべての値と一致する ID を含む追加のテーブルを生成できます。次に、必要な正確な値を検索できます。

または、EndRange - StartRange の最大値を計算し、それを MaxRange と呼びます。StartRange にインデックスを作成し、クエリを次のように変更します。

 SELECT ID FROM BigTable 
    WHERE StartRange BETWEEN ('5000000' - MaxRange) AND '5000000' 
      AND '5000000' BETWEEN StartRange AND EndRange;

これで、最初の BETWEEN 句インデックス可能になり、少数の行が返されるはずです。2 番目の BETWEEN 句は、行の小さなサブセットにのみ適用されます。明らかに、これは MaxRange の安全な値を事前に計算できることに依存しています。うまくいけば、この数値を示す範囲の実際の最大値があることを願っています。

于 2012-10-03T00:20:42.363 に答える