3

データベースに、時間ごとのログデータを格納するテーブルがあります。1日で、データベースに100万行が存在する可能性があります。時間は一定の間隔ではありません。時間を含むいくつかのインデックスがあります。私がやりたいのは、時間間隔ごとに1行の行のセットを返すクエリを作成することです。たとえば、1日15分ごとに1行を返すクエリを実行できます。これにより、24 * 60=96行が返されます。返される各行は、実際には、要求された間隔の前のデータベース内の最も近い行になります(データベース内のデータは要求された間隔と等しくないため)。

私はそれをどうやってやるのか途方に暮れています。ギガバイトを超えるデータをメモリにロードするのは遅すぎるため、特定のインデックスのセットと時間間隔についてすべての行をクエリすることはできません。SQLを使用してこれを行う効率的な方法はありますか?MySQLデータベースを使用しています。テーブルのインデックスなどを変更することもできます...

TIME

11:58
12:03
12:07
12:09
12:22
12:27
12:33
12:38
12:43
12:49
12:55

これを12:00から1:00までの15分間隔でクエリしたい場合は、次のようになります。

11:58 (nearest 12:00)
12:09 (nearest 12:15)
12:27 (nearest 12:30)
12:43 (nearest 12:45)
12:55 (nearest 1:00) 

簡単にできる場合は、時間を数値として保存することもできます(つまり、1970年からのミリ秒)。上記のクエリでは、これは900000ミリ秒の間隔になります。

4

3 に答える 3

4

だから、私は次のようなことを考えていました:

SELECT 
  MIN(timeValue)
FROM e
GROUP BY (to_seconds(timeValue) - (to_seconds(timeValue) % (60 * 5)))

..それを行いますが、これはテーブル全体のMIN(timeValue)のみを返します。最も近い5分に丸められた秒が独自の列にある場合に機能します。

SQLフィドルを参照してください

Andiryごとに編集します。これは機能します:(http://sqlfiddle.com/#!2/bb870/6

SELECT MIN(t)
FROM e
GROUP BY to_seconds(t) DIV (60 * 5)

しかし、これは1つの行を与えるだけです:(http://sqlfiddle.com/#!2/bb870/7

SELECT MIN(t)
FROM e
GROUP BY to_seconds(t) - (to_seconds(t) % (60 * 5))

誰もが理由を知っていますか?

于 2012-05-17T21:01:30.787 に答える
0

1つのクエリですべてを実行するための良い方法を考えることはできません。おそらく他の誰かがより良い方法を考えることができますが、おそらくあなたはこのようなものを使うことができます:

$startTime = mktime(12, 0);
$endTime = mktime(13, 0);
$queries = array();
for ($i = $startTime; $i <= $endTime; $i += 900)
    $queries[] = "SELECT MAX(timeValue) FROM table1 WHERE timeValue < '". date("G:i", $i) ."'";

$query = implode("\nUNION\n", $queries);

これは、PHPを使用していることを前提としていることに気づきました。そうでない場合は、次のような結果のクエリを使用してください。

SELECT MAX(timeValue) FROM table1 WHERE timeValue < '12:00'
UNION
SELECT MAX(timeValue) FROM table1 WHERE timeValue < '12:15'
UNION
SELECT MAX(timeValue) FROM table1 WHERE timeValue < '12:30'
UNION
SELECT MAX(timeValue) FROM table1 WHERE timeValue < '12:45'
UNION
SELECT MAX(timeValue) FROM table1 WHERE timeValue < '13:00'

<比較がこれらの文字列値で100%正しく機能するかどうかはわかりませんが、UNIXタイムスタンプ(または、1970年以降のミリ秒)に切り替えることをお勧めします。文字列ではなく、日付/時刻の整数値を使用する方が常に簡単であることがわかりました。

于 2012-05-17T19:59:30.960 に答える
0

関数の使用は非常に簡単で、パフォーマンスへの大きな影響には気づいていませんが、時間の間にある行数によっては、カーソルの方がプリフォームが優れている可能性があります。

CREATE TABLE TEST_TIMES (EventTime datetime)
-- skipping INSERTS of your times

CREATE FUNCTION fn_MyTimes ( @StartTime datetime, @EndTime datetime, @Minutes int )
    RETURNS @TimeTable TABLE (TimeValue datetime)
AS BEGIN
    DECLARE @CurrentTime datetime
    SET @CurrentTime = @StartTime
    WHILE @CurrentTime <= @EndTime
    BEGIN
        INSERT INTO @TimeTable VALUES (@CurrentTime)
        SET @CurrentTime = DATEADD(minute, @Minutes, @CurrentTime)
    END
    RETURN
END

CREATE FUNCTION fn_ClosestTime ( @CheckTime datetime )
    RETURNS datetime
AS BEGIN
    DECLARE @LowerTime datetime, @HigherTime datetime

    SELECT @LowerTime = MAX(EventTime)
    FROM TEST_TIMES
    WHERE EventTime <= @CheckTime

    SELECT @HigherTime = MAX(EventTime)
    FROM TEST_TIMES
    WHERE EventTime >= @CheckTime

    IF @LowerTime IS NULL RETURN @HigherTime -- both null?  then null
    IF @HigherTime IS NULL RETURN @LowerTime

    IF DATEDIFF(ms, @LowerTime, @CheckTime) < DATEDIFF(ms, @CheckTime, @HigherTime)
        RETURN @LowerTime
    RETURN @HigherTime
END

SELECT TimeValue, dbo.fn_ClosestTime(TimeValue) as ClosestTime
FROM fn_MyTimes('2012-05-17 12:00', '2012-05-17 13:00', 15)

結果:

TimeValue               ClosestTime
----------------------- -----------------------
2012-05-17 12:00:00.000 2012-05-17 11:58:00.000
2012-05-17 12:15:00.000 2012-05-17 12:09:00.000
2012-05-17 12:30:00.000 2012-05-17 12:27:00.000
2012-05-17 12:45:00.000 2012-05-17 12:43:00.000
2012-05-17 13:00:00.000 2012-05-17 12:55:00.000
于 2012-05-17T21:47:48.030 に答える