MySQL Data Smoothing - PullRequest
       22

MySQL Data Smoothing

1 голос
/ 17 марта 2012

У меня есть база данных 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

Созданный ВИД должен выглядеть следующим образом:

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 меняется).

Таким образом, следующие строки должны быть рассчитаны следующим образом:

  • 1-я строка столбца 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 </strong>
  • 2-я строка столбца mem_5_min_avg (432 + 490 + 501 + 396) / 4 = 1819/4 = 454,75 = 455
  • 3-я строка столбца mem_5_min_avg (490 + 501 + 396) / 3 = 1387/4 = 462,33 = 463
  • 4-я строка столбца mem_5_min_avg (501 + 396) / 2 = 897/2 = 448,5 = 449
  • 5-я строка столбца mem_5_min_avg 396 <- здесь мы не суммируем ни одной строки, потому что даже если следующее измерение будет выполнено в течение 5 минут, mem_total изменился. </strong>
  • 6-я строка столбца mem_5_min_avg (404 + 801) / 2 = 1205/2 = 602,5 = 603
  • 7-я строка столбца mem_5_min_avg 801

После вычисления mem_5_min_avg мне нужен столбец mem_rate_usage , который показывает простую скорость использования памяти в процентах.

mem_rate_usage = mem_5_min_avg / mem_total

Например, 3-я строка mem_rate_usage должна быть рассчитана следующим образом: 463/1024 = 0,45214844, а последний столбец - следующим образом: 801/1536 = 0,52148438

Понятия не имею, как к этому подойти. Я пробовал функцию «AVG» в сочетании с «GROUP by», но на самом деле я не хочу ничего группировать здесь. Я хочу, чтобы в созданном представлении было одинаковое количество строк и данных, а также сглаженные данные и скорости.

Ответы [ 2 ]

0 голосов
/ 18 марта 2012
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
0 голосов
/ 17 марта 2012

ОБНОВЛЕНИЕ 2:

Улучшен запрос, но он все еще медленный.Я понял, что TIMESTAMPDIFF намного медленнее, чем прямое сравнение между UNIX_TIMESTAMP.Таким образом, изменяя код UPDATE 1, мы получаем почти 20% -ное улучшение скорости.

Увеличение также параметра innodb_buffer_pool_size в my.cnf помогло значительно увеличить скорость.

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 строками, которые у меня есть.Выполнение занимает 7,5 секунды, если я ограничиваю запрос 30 строками, и более 20 секунд, если я ограничиваю его 100. Я предполагаю, что для 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
...