1

メモリ データとタイムスタンプを保持する MySQL データベースがあります。システムで使用されているメモリや使用可能なメモリの合計などの非常に単純なデータ。ここで、このデータを使用していくつかの簡単な計算を行った後、MySQL VIEW を作成して、ある程度のデータ平滑化を実現したいと考えています (平均にローリング ウィンドウを使用)。

最初のテーブルは次のようになります。

id |date                     |mem_used    |mem_total
1  |2012-03-16 23:29:05      |467         |1024
2  |2012-03-16 23:30:05      |432         |1024
3  |2012-03-16 23:31:05      |490         |1024
4  |2012-03-16 23:33:05      |501         |1024
5  |2012-03-16 23:35:05      |396         |1024
6  |2012-03-16 23:39:05      |404         |1536
7  |2012-03-16 23:43:05      |801         |1536

作成された VIEW は次のようになります。

id |date                     |mem_used    |mem_total    |mem_5_min_avg    |mem_rate_usage
1  |2012-03-16 23:29:05      |467         |1024         |473              |0.46191406
2  |2012-03-16 23:30:05      |432         |1024         |455              |0.44433594
3  |2012-03-16 23:31:05      |490         |1024         |463              |0.45214844
4  |2012-03-16 23:33:05      |501         |1024         |449              |0.43847656
5  |2012-03-16 23:35:05      |396         |1024         |396              |0.38671875
6  |2012-03-16 23:39:05      |404         |1536         |603              |0.39257813
7  |2012-03-16 23:43:05      |801         |1536         |801              |0.52148438

要件:

最初の 3 列は同じですが、列mem_5_min_avgには、 mem_totalが同じ ( mem_totalが変化している)場合、次の 5 分間の平均使用メモリが含まれている必要があります。

したがって、次の行は次のように計算する必要があります。

  • mem_5_min_avg 列の 1 行目 (467+432+490+501)/4 = 1890/4 = 472.5 = 473 <- 2012-03-16 23:29:05 プラス 5 分 2012-03 なので、ここで 4 行を合計します-16 23:34:05
  • mem_5_min_avg 列の 2 行目 (432+490+501+396)/4 = 1819/4 = 454.75 = 455
  • mem_5_min_avg 列の 3 行目 (490+501+396)/3 = 1387/4 = 462.33 = 463
  • mem_5_min_avg 列の 4 行目 (501+396)/2 = 897/2 = 448.5 = 449
  • mem_5_min_avg 列の 5 行目 396 <- 次の測定が 5 分以内であっても、mem_total が変化しているため、ここでは行を合計しません。
  • mem_5_min_avg 列の 6 行目 (404+801)/2 = 1205/2 = 602.5 = 603
  • mem_5_min_avg 列の 7 行目 801

mem_5_min_avgが計算された後、mem_rate_usage列が必要です。これは、パーセンテージで指定されたメモリ使用量の単純な割合を示します。

mem_rate_usage = mem_5_min_avg / mem_total

たとえば、mem_rate_usage の 3 行目は463 /1024=0.45214844 のように計算する必要がありますが、最後の列は 801/1536=0.52148438 のように計算する必要があります。

これにアプローチする方法についての手がかりがありません。「GROUP by」と組み合わせて「AVG」機能を試してみましたが、実際にはここで何もグループ化したくありません。作成されたビューに同じ数の行とデータを持ち、さらに平滑化されたデータとレートが必要です。

4

2 に答える 2

0
SELECT
    rrd1.id,
    rrd1.date,
    rrd1.mem_used,
    rrd1.mem_total,
    (
        SELECT
            CEILING(AVG(rrd2.mem_used))
        FROM
            rrd rrd2
        WHERE
            rrd2.date >= rrd1.date AND
            rrd2.date <= AddTime(rrd1.date, '00:05')
    ) AS mem_5_min_avg
FROM
    rrd rrd1
于 2012-03-17T23:41:59.723 に答える
0

更新 2:

クエリをさらに改善しましたが、まだ遅いです。TIMESTAMPDIFF は、UNIX_TIMESTAMP を直接比較するよりもはるかに遅いことに気付きました。したがって、このように UPDATE 1 のコードを変更すると、ほぼ 20% の速度向上が得られます。

my.cnf のinnodb_buffer_pool_sizeオプションも増やすと、速度が大幅に向上しました。

SELECT  `date` ,  `mem_used` ,  `mem_total` , `mem_5_min_avg` , 
(`mem_5_min_avg` / `mem_total`) AS mem_usage_rate
FROM (
   SELECT *, (
      SELECT CEILING( AVG( mem_used ) )
      FROM `data` AS t2
      WHERE UNIX_TIMESTAMP(t2.date) - UNIX_TIMESTAMP(t1.date) <=300 
      AND t2.date >= t1.date
      AND t1.mem_total = t2.mem_total
      AND t1.host_id = t2.host_id
   ) AS mem_5_min_avg
   FROM `data` AS t1
) AS t1

更新 1:クエリを改善して 2 倍の速度を提供しましたが、大きなテーブルではまだ非常に低速です。

SELECT  `date` ,  `mem_used` ,  `mem_total` , `mem_5_min_avg` , 
(`mem_5_min_avg` / `mem_total`) AS mem_usage_rate
FROM (
   SELECT *, (
      SELECT CEILING( AVG( mem_used ) )
      FROM `data` AS t2
      WHERE TIMESTAMPDIFF(
      MINUTE , t1.date, t2.date ) <=5
      AND t2.date >= t1.date
      AND t1.mem_total = t2.mem_total
   ) AS mem_5_min_avg
   FROM `data` AS t1
) AS t1

初期投稿

ubuntuforums で同じ質問をしたところ、TeoBigusGeekus は、動作する必要があるのとまったく同じように動作すると答えましたが、100000 行を超える大きなテーブルでは非常に遅いです。クエリを 30 行に制限すると実行に 7.5 秒かかり、100 行に制限すると 20 秒以上かかります。100000 行では永遠にかかると思います。とにかく、ここでの解決策に興味がある人にとっては、次のとおりです。

SELECT  `date` ,  `mem_used` ,  `mem_total` , (
   SELECT CEILING( AVG( mem_used ) )
   FROM mytable AS t2
   WHERE TIMESTAMPDIFF(
   MINUTE , t1.date, t2.date ) <=5
   AND t2.date >= t1.date
   AND t1.mem_total = t2.mem_total
) AS mem_5_min_avg, (
   SELECT CEILING( AVG( mem_used ) ) / mem_total
   FROM mytable AS t3
   WHERE TIMESTAMPDIFF(
   MINUTE , t1.date, t3.date ) <=5
   AND t3.date >= t1.date
   AND t1.mem_total = t3.mem_total
) AS mem_rate_usage
FROM mytable AS t1
于 2012-03-17T16:49:43.177 に答える