1

次のようなデータベーステーブルがあります。

id | macaddr | load | timestamp
=========================================
 1 | 0011111 |   17 | 2012-02-07 10:00:00
 1 | 0011111 |    6 | 2012-02-07 12:00:00
 2 | 0022222 |    3 | 2012-02-07 12:00:03
 3 | 0033333 |    9 | 2012-02-07 12:00:04
 4 | 0022222 |    4 | 2012-02-07 12:00:06
 5 | 0033333 |    8 | 2012-02-07 12:00:10
...

ここで、今日、昨日、今週、今月など、さまざまな期間のすべてのデバイス (= mac アドレス) の平均負荷を計算したいと思います。

平均負荷は、最初に異なる時点 (サンプル日付) での全体的な負荷の合計を見つけてから、これらのサンプル日付の負荷合計の平均を計算することによって計算できます。たとえば、最後の 10 秒間 (現在は 2012 年 2 月 7 日 12:00:10) の平均負荷が必要な場合は、サンプルの日付を 12:00:02、12:00 にすることができます。 04、12:00:06、12:00:08、12:00:10。次に、各デバイスの最新の負荷値を合計して、負荷の合計を計算します。

2012-02-07 12:00:02 |  6  [= load(id=2)]
2012-02-07 12:00:04 | 18  [= load(id=2) + load(id=3) + load(id=4)]
2012-02-07 12:00:06 | 19  [= load(id=2) + load(id=4) + load(id=5)]
2012-02-07 12:00:08 | 19  [= load(id=2) + load(id=4) + load(id=5)]
2012-02-07 12:00:10 | 18  [= load(id=2) + load(id=5) + load(id=6)]

デバイスの負荷値は、たとえば 1 時間より古い場合は無視されます (ここでは id=1 に発生)。この場合、平均は 16 になります。

現在、非常に遅い多くの「UNION ALL」ステートメントを含むかなり複雑なクエリを生成しています。

SELECT avg(l.load_sum) as avg_load
FROM (
    SELECT sum(so.load) AS load_sum 
    FROM (
        SELECT * 
        FROM (
            SELECT si.macaddr, si.load 
            FROM sensor_data si WHERE si.timestamp > '2012-02-07 11:00:10' AND si.timestamp < '2012-02-07 12:00:10'
            ORDER BY si.timestamp DESC 
        ) AS sm
        GROUP BY macaddr
    ) so
    UNION ALL
    [THE SAME THING AGAIN WITH OTHER TIMESTAMPS]
    UNION ALL
    [AND AGAIN]
    UNION ALL
    [AND AGAIN]
    ...
) l

ここで、1 か月の平均負荷を計算したいとします。1 時間ごとのサンプル日付では、UNION ALL ステートメントを使用して 30x24=720 のクエリを結合する必要があります。私のマシンでは、クエリ全体が完了するまでに 1 分近くかかります。UNION ALL ステートメントを使用しない方がはるかに優れたソリューションがあると確信しています。ただし、Web 上で役立つものは何も見つかりませんでした。したがって、私はあなたの助けにとても感謝しています!

4

3 に答える 3

1

unix タイムスタンプの一部を使用します。まず、1 時間 (3600 秒) の平均を計算します。

SELECT
  macaddr, 
  sum(CAST(load AS float))/CAST(count(*) AS float) AS loadavg,
  FLOOR(UNIX_TIMESTAMP(`timestamp`)/3600) AS hourbase
FROM sensor_data
GROUP BY macaddr,FLOOR(UNIX_TIMESTAMP(`timestamp`)/3600)

次に、その月の平均をとります

SELECT 
  avg(loadavg) as monthlyavg,
  macaddr
FROM (
    SELECT
      macaddr, 
      sum(CAST(load AS float))/CAST(count(*) AS float) AS loadavg,
      FLOOR(UNIX_TIMESTAMP(`timestamp`)/3600) AS hourbase
    FROM sensor_data
    WHERE `timestamp` BETWEEN '2012-01-07 12:00:00' AND '2012-02-07 11:59:59'
    GROUP BY macaddr,FLOOR(UNIX_TIMESTAMP(`timestamp`)/3600)
) AS hourlies
GROUP BY macaddr, hourbase
于 2012-02-07T22:16:03.247 に答える
0

自分で物事を簡単にするために、時間部分の後に有効数字のない日時を返す「時間」関数を作成する必要があります。したがって、現在 (2012 年 2 月 2 日午後 5 時 5 分) は 2012-02-07 17:00 になります。時間関数のコードは次のとおりです。

select dateadd(hh, DATEPART(hh, current_timestamp), DATEADD(dd, 0, datediff(dd, 0, current_timestamp)))

(current_timestamp上記のコードを、時間関数の datetime パラメーターに置き換えます。dbo.fnHour() として作成したと仮定し、datetime パラメーターを取ります。

次に、dbo.fnHour() をパーティショニング関数として使用して、必要なものを照会できます。SQL は次のようになります。

select 
    avg(load) as avg_load
from (
    select dbo.fnHour(si.timestamp) [hour], macaddr, sum(load) as [load]
    from 
        sensor_data si 
    where 
        si.timestamp >= dateadd(mm, -1, current_timestamp)
    group by 
        dbo.fnHour(si.timestamp), macaddr
) as f

私はそれをテストしていないので、タイプミスがあるかもしれませんが、これで十分です。

于 2012-02-07T22:12:08.693 に答える
0

あなたがやろうとしていることを誤解しているかもしれません。サンプリングを使用する必要があるよりもはるかに複雑にしているようです。おそらく、結果がどのように見えるかのサンプルを提供することで、人々は特定のケースに対してより良い解決策を提供できるようになります。

mysql> SELECT * FROM `test`;
+----+-----+------+------------+
| id | mac | load | when       |
+----+-----+------+------------+
|  1 |   1 |   10 | 2012-02-01 |
|  2 |   1 |   20 | 2012-01-01 |
|  3 |   2 |   60 | 2011-09-01 |
+----+-----+------+------------+

mysql> SELECT avg(`sum_load`)
    -> FROM 
    -> (
    ->    SELECT sum( `load` ) as sum_load
    ->    FROM `test`
    ->    WHERE `when` > '2011-01-15'
    ->    GROUP BY `mac`
    -> ) as t1;
+-----------------+
| avg(`sum_load`) |
+-----------------+
|         45.0000 |
+-----------------+

mysql> SELECT avg(`sum_load`)
    -> FROM 
    -> (
    ->    SELECT sum( `load` ) as sum_load
    ->    FROM `test`
    ->    WHERE `when` > '2011-01-15' AND `when` < '2012-01-15'
    ->    GROUP BY `mac`
    -> ) as t1;
+-----------------+
| avg(`sum_load`) |
+-----------------+
|         40.0000 |
+-----------------+
于 2012-02-07T22:12:40.627 に答える