まず、テーブルのエントリ数を1時間ごとに要約します。
SELECT CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) hour,
COUNT(*) samplecount
FROM table
GROUP BY CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME)
これで、6分ごと(1時間に10回)に何かをログに記録すると、すべてのsamplecount値は10になります。この式:CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME)
毛むくじゃらに見えますが、タイムスタンプを分と秒をゼロにすることで、タイムスタンプが発生する時間に切り捨てるだけです。
これはかなり効率的であり、始めることができます。 entry_time列にインデックスを付けて、クエリを、たとえば、ここに示すように昨日のサンプルに制限できると、非常に効率的です。
SELECT CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) hour,
COUNT(*) samplecount
FROM table
WHERE entry_time >= CURRENT_DATE - INTERVAL 1 DAY
AND entry_time < CURRENT_DATE
GROUP BY CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME)
しかし、サンプルが欠落している時間全体を検出するのはあまり得意ではありません。また、サンプリングのジッターにも少し敏感です。つまり、時間の最上位のサンプルが0.5秒早い(10:59:30)場合と0.5秒遅い(11:00:30)場合は、1時間ごとの要約カウントがオフになります。したがって、この時間の要約(または日の要約、または分の要約など)は防弾ではありません。
完全に正しく処理するには、自己結合クエリが必要です。それはもう少し毛玉であり、ほとんど効率的ではありません。
番号付きのサンプルを使用して、このような仮想テーブル(サブクエリ)を作成することから始めましょう。 (これはMySQLの苦痛です。他の高価なDBMSを使用すると、簡単になります。関係ありません。)
SELECT @sample:[email protected]+1 AS entry_num, c.entry_time, c.value
FROM (
SELECT entry_time, value
FROM table
ORDER BY entry_time
) C,
(SELECT @sample:=0) s
この小さな仮想テーブルは、entry_num、entry_time、valueを提供します。
次のステップでは、それを結合します。
SELECT one.entry_num, one.entry_time, one.value,
TIMEDIFF(two.value, one.value) interval
FROM (
/* virtual table */
) ONE
JOIN (
/* same virtual table */
) TWO ON (TWO.entry_num - 1 = ONE.entry_num)
これにより、JOINのON句によって制御される単一のエントリによってオフセットされたテーブルが互いに隣接して整列します。
最後に、このテーブルからinterval
を使用して値を選択します しきい値よりも大きく、欠落しているサンプルの直前のサンプルの時間があります。
全体的な自己結合クエリはこれです。毛玉だと言った。
SELECT one.entry_num, one.entry_time, one.value,
TIMEDIFF(two.value, one.value) interval
FROM (
SELECT @sample:[email protected]+1 AS entry_num, c.entry_time, c.value
FROM (
SELECT entry_time, value
FROM table
ORDER BY entry_time
) C,
(SELECT @sample:=0) s
) ONE
JOIN (
SELECT @sample2:[email protected]+1 AS entry_num, c.entry_time, c.value
FROM (
SELECT entry_time, value
FROM table
ORDER BY entry_time
) C,
(SELECT @sample2:=0) s
) TWO ON (TWO.entry_num - 1 = ONE.entry_num)
大きなテーブルで本番環境でこれを実行する必要がある場合は、データのサブセットに対して実行することをお勧めします。たとえば、過去2日間のサンプルに対して毎日それを行うことができます。これはかなり効率的であり、真夜中に欠落しているサンプルを見落とさないようにすることもできます。これを行うには、行番号が小さい仮想テーブルは次のようになります。
SELECT @sample:[email protected]+1 AS entry_num, c.entry_time, c.value
FROM (
SELECT entry_time, value
FROM table
ORDER BY entry_time
WHERE entry_time >= CURRENT_DATE - INTERVAL 2 DAY
AND entry_time < CURRENT_DATE /*yesterday but not today*/
) C,
(SELECT @sample:=0) s