8

次のテーブルがあるとしましょう:

CREATE TABLE `occurences` (
  `object_id` int(10) NOT NULL,
  `seen_timestamp` int(10) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8

これには、オブジェクトの ID (一意ではなく、繰り返します) と、このオブジェクト ID が観測されたときのタイムスタンプが含まれます。

監視は 24 時間 365 日実行されており、オブジェクト ID が出現するたびに現在のタイムスタンプが挿入されます。

ここで、任意の 10 分間に少なくとも 7 回表示されたすべてのオブジェクト ID を選択するクエリを作成します。

侵入検知のように機能するはずです。

同様のアルゴリズムが、無効な SSH ログインをチェックする denyhost スクリプトで使用されます。設定された期間中に設定された数の発生が見つかった場合、IP をブロックします。

良い提案はありますか?

4

3 に答える 3

4

これはうまくいくはずです:

SET @num_occurences = 7; -- how many occurences should occur in the interval
SET @max_period = 10; -- your interval in seconds

SELECT offset_start.object_id FROM 
(SELECT @rownum_start := @rownum_start+1 AS idx, object_id, seen_timestamp 
 FROM occurences, (SELECT @rownum_start:=0) r ORDER BY object_id ASC, seen_timestamp ASC) offset_start
JOIN
(SELECT @rownum_end := @rownum_end + 1 AS idx, object_id, seen_timestamp 
 FROM occurences, (SELECT @rownum_end:=0) r ORDER BY object_id ASC, seen_timestamp ASC) offset_end
   ON offset_start.object_id = offset_end.object_id 
  AND offset_start.idx + @num_occurences - 1 = offset_end.idx
  AND offset_end.seen_timestamp - offset_start.seen_timestamp <= @max_period
GROUP BY offset_start.object_id;

コードに移動@num_occurences@num_occurencesて、これらをステートメントのパラメーターとして設定できます。@rownum_startクライアントによっては、クエリの初期化をクエリの前に移動することもできます@rownum_end。これにより、クエリのパフォーマンスが向上する可能性があります(ただし、両方のバージョンの説明を見て直感的にテストする必要があります)

仕組みは次のとおりです。

テーブル全体を 2 回選択offset_startし、 の各行をoffset_endのオフセットを持つ行と結合し@num_occurencesます。(これは、@rownum_*変数を使用して各行のインデックスを作成し、他の rdbms で知られている row_number() 機能をシミュレートして行われます)。
次に、2 つの行が同じ object_id を参照しており、期間の要件を満たしているかどうかを確認します。
これはオカレンス行ごとに行われるため、オカレンス数が実際に より大きい場合、object_id は複数回返されるため、返されるs を一意@max_occurencesにするために最後にグループ化されます。object_id

于 2012-04-17T10:10:06.437 に答える
1

次のステートメントを使用できます。

SELECT oc1.object_id 
    FROM occurences oc1 
        JOIN occurences oc2 ON oc1.object_id = oc2.object_id  
            AND oc1.seen_timestamp >= (oc2.seen_timestamp -600)
            AND oc1.seen_timestamp < oc2.seen_timestamp
    GROUP BY oc1.object_id, oc1.seen_timestamp
    HAVING COUNT(oc2.object_id)>=7;

あまり高速ではなく、あまりきれいでもありません。誰かがより良い解決策を見つけたら教えてください!

于 2012-04-17T10:45:45.640 に答える
1

あなたは試すことができます

SELECT COUNT(seen_timestamp) AS tot FROM occurences
WHERE seen_timestamp BETWEEN
    DATE_ADD(your_dt, INTERVAL -10 MINUTES) AND your_dt
GROUP BY object_id
HAVING tot >= 7

int(10)forを使用する理由がわかりませんseen_timestamp: a datetime...を使用できます

于 2012-04-05T12:37:38.077 に答える