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列应该包含接下来 5 分钟的平均使用内存,因为mem_total是相同的(mem_total正在变化)。

因此,应按如下方式计算以下行:

  • mem_5_min_avg 列的第一行 (467+432+490+501)/4 = 1890/4 = 472.5 = 473 <- 我们在这里总结了 4 行,因为 2012-03-16 23:29:05 加上 5 分钟 2012-03 -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

我不知道如何处理这个问题。我已经尝试将“AVG”功能与“GROUP by”结合使用,但我实际上并不想在这里对任何东西进行分组。我想在创建的视图中拥有相同数量的行和数据,另外还有平滑的数据和速率。

4

2 回答 2

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:我改进了查询以提供两倍的速度,但对于我的大表来说仍然很慢。

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 回答
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 回答