テーブルには2つのフィールドがあります
| UniqueKey | TimeStamp |
-------------------------
| xfsddddq | 1024125412 |
| xfstttdx | 1024125413 |<
| xfsdxxau | 1024125415 |
推定では1000万件のレコードがあります。 UniqueKey
が(CURRENT_TIME - 5MINS)
内に存在するかどうかを確認する必要があります。
テーブルmydb.mytable
UniqueKeyとtimeStampを使用して、UniqueKey
が過去5分以内に存在するかどうかを確認するには、これを実行します
SELECT COUNT(1) FROM mydb.mytable
WHERE UniqueKey = ????
AND timeStamp >= ( NOW() - INTERVAL 5 MINUTE );
または
SELECT COUNT(1) FROM mydb.mytable
WHERE UniqueKey = ????
AND timeStamp >= ( NOW() - INTERVAL 300 SECOND );
値は何を示していますか???
UniqueKeyに一意のインデックスがあることを確認してください。
タイムスタンプはUNIXタイムスタンプなので、 UNIX_TIMESTAMP() 関数を使用してコードを調整します
SELECT COUNT(1) FROM mydb.mytable
WHERE UniqueKey = ????
AND timeStamp >= UNIX_TIMESTAMP(NOW() - INTERVAL 5 MINUTE);
これを実行するクエリは次の形式になります。
SELECT t.UniqueKey
FROM mytable t
WHERE t.UniqueKey = ?
AND t.timeStamp >= NOW() - INTERVAL 5 MINUTE
AND t.timeStamp <= NOW()
LIMIT 1
(このクエリでは、timeStamp
列がデータ型[〜#〜] timestamp [〜#〜]として定義されていると想定しています。)
クエリは1行または0行を返します。これは、指定したUniqueKey
が過去5分間に「存在する」か、「存在しない」ことを示します。
そのクエリはインデックスを要求します:
... ON mytable (UniqueKey,timeStamp)
UniqueKey
がテーブル内で本当に一意である場合、UniqueKeyのみのインデックスで十分です。列のデータ型、ストレージエンジン、既存のキー/インデックス、データ分布などに関する知識がなければ、何が最善かを実際に判断することはできません。
[〜#〜]更新[〜#〜]
(上記の答えはStackOverflowからコピーされたもので、質問が最初に表示されました。)
OPは質問をサンプルデータで更新し、timeStamp
列がおそらく[〜#〜] not [〜#〜] MySQLであることを示しています[〜#〜] timestamp [〜#〜]ですが、整数値のようです。
整数データ型(INT、BIGINTなど)として格納されていると想定し、整数値が日時順に昇順であるとすると、最も効率的なクエリは次の形式になります。
SELECT t.UniqueKey
FROM mytable t
WHERE t.UniqueKey = ?
AND t.timeStamp >= ?
AND t.timeStamp <= ?
LIMIT 1
値は述語で提供されます(timeStamp
と比較するために整数値であると想定されています。これは単なる前提であり、実際には整数値であるという知識はありません。また、知識もありません。日時がどのようにエンコードされるかについて。
timeStamp
値は、エポックの開始(UTC 1970年1月1日の真夜中)からの秒数を表す整数である可能性が非常に高いです。これは広く採用されている規則ですが、timeStamp
という名前のすべての列にこの方法でエンコードされた値があるという「規則」ではなく、単なる規則です。
だから、私は仮定に基づいてさらなる提案をすることをためらっています。 MySQLは変換を可能にする関数を提供しますが、いくつかは非常に便利です。しかし、実際にtimeStamp
列に格納されている値がわからない。これらの推奨事項は、仮定に基づいています。
最初に、UniqueKey
のタイプをテキストからINTに変更する必要があります。マルチバイト文字に照合順序を適用する必要がないため、数値検索は文字列検索よりも高速です。
次に、レコードとセットを区別するために必要なすべてのフィールドを含む複雑なインデックスを作成する必要があります。ここでの秘訣-インデックス定義でフィールドをリストする順序は非常に重要であり、高速化するクエリによって異なります。クエリ用
_SELECT * FROM table
WHERE UniqueKey = someValue
AND TimeStamp > NOW() - INTERVAL 5 MINUTE
ORDER BY TimeStamp DEC
LIMIT 1;
_
最小の結果セットの生成からより広い条件までの範囲のインデックスフィールドを順序付ける必要があります。テーブルに1時間で1000万レコードが含まれている場合、5分の部分には約1/12または800kレコードが含まれます。 1000個の一意のキーがある場合次に、同じ一意のキーを持つ約1/1000または100kのレコードがあります。したがって、インデックスは最初にUniqueKeyで定義し、次にTimestampで定義する必要があります。
_CREATE TABLE ...
. . . . .
INDEX `Key_TS` (`UniqueKey`, `TimeStamp`)
. . . . .
_
5秒の間隔内で選択する場合は、タイムスタンプがより狭い基準になる可能性があるため、インデックス定義でUniqueKeyの前にタイムスタンプフィールドを記述する必要があります。インデックスをその場で変更できない限り、同じフィールドで異なる順序で2つのインデックスを定義する必要があります。
_CREATE TABLE ...
. . . . .
INDEX `UKey_TS` (`UniqueKey`, `TimeStamp`)
INDEX `TS_UKey` (`TimeStamp`, `UniqueKey`)
. . . . .
_
次に、推測する代わりに、mysql
に特定のインデックスを使用することを明示的に強制する必要があります。
_SELECT * FROM table USE INDEX (`UKey_TS`)
WHERE UniqueKey = someValue
AND TimeStamp > NOW() - INTERVAL 5 MINUTE
ORDER BY TimeStamp DEC
LIMIT 1;
_
どのインデックスがより良い結果を得るかをテストする必要があります。インデックスは高価なので、本当に必要なインデックスのみを作成してください。
もう1つの提案は、クエリ内で一定であるすべての値を事前計算することです。実際、NOW() - INTERVAL 5 MINUTE
は、_UniqueKey = someValue
_を持つレコードの数だけ再計算されます。値を変数に事前計算すると、計算は1回だけ実行されます。
_SET @min_ts = NOW() - INTERVAL 5 MINUTE;
SELECT * FROM table USE INDEX (`UKey_TS`)
WHERE UniqueKey = someValue
AND TimeStamp > @min_ts
ORDER BY TimeStamp DEC
LIMIT 1;
_