Эффективный способ получить суммы на основе нескольких временных интервалов? - PullRequest
1 голос
/ 07 мая 2020

Есть ли эффективный способ получить суммы за несколько временных диапазонов для нескольких групп (пример ниже)?

Я использую MySQL 8.

PS: Я очень старался сформулировать этот вопрос настолько ясно, насколько это возможно. Я с радостью приму предложения, чтобы сделать его более ясным / понятным ...


OBS:

  • Учитывая '2020-05- 07 16:20:00 'как «текущее время».

  • Каждый идентификатор представляет одну автомат c плювиометри c станцию ​​(датчик дождя)

RAW ТАБЛИЦА:

SELECT* FROM pluv_reg ORDER BY dth DESC;

id   dth                    valor
1    2020-05-07 16:20:00    5.0
2    2020-05-07 16:20:00    5.0
3    2020-05-07 16:20:00    5.0
4    2020-05-07 16:20:00    5.0
1    2020-05-07 16:15:00    5.0
2    2020-05-07 16:15:00    5.0
...

ЖЕЛАТЕЛЬНЫЙ ВОЗВРАТ:

id   dth                    m05     m15    m30     h01     h24      h48      h96
1    2020-05-07 16:20:00    5.0    15.0    60.0    60.0    100.0    100.0    196.0
2    2020-05-07 16:20:00    5.0    15.0    60.0    60.0    100.0    100.0    197.0
3    2020-05-07 16:20:00    5.0    15.0    60.0    60.0    100.0    100.0    198.0
4    2020-05-07 16:20:00    5.0    15.0    60.0    60.0    100.0    100.0    199.0
1    2020-05-07 16:15:00    5.0    15.0    55.0    55.0    95.0     95.0     191.0
2    2020-05-07 16:15:00    5.0    15.0    55.0    55.0    95.0     95.0     192.0
3    2020-05-07 16:15:00    5.0    15.0    55.0    55.0    95.0     95.0     193.0
...

LEGEND
Column m05 -> Sum of "valor" of the last 05 minutes for that "id" at that time
...
Column m30 -> Sum of "valor" of the last 30 minutes for that "id" at that time
...
Column h48 -> Sum of "valor" of the last 48 hours for that "id" at that time

ТЕКУЩИЙ ЗАПРОС:

SELECT *
FROM (
    SELECT pluv_reg.id,
            pluv_reg.dth,
            SUM(pluv_reg.valor)  OVER w05 AS 'm05',
            SUM(pluv_reg.valor)  OVER w15 AS 'm15',
            SUM(pluv_reg.valor)  OVER w30 AS 'm30',
            SUM(pluv_reg.valor)  OVER w1 AS 'h01',
            SUM(pluv_reg.valor)  OVER w24 AS 'h24',
            SUM(pluv_reg.valor)  OVER w48 AS 'h48',
            SUM(pluv_reg.valor)  OVER w96 AS 'h96'
    FROM pluv_reg

    # this WHERE clause ensures that all the rows I need have the correct values ______________________________
    WHERE pluv_reg.dth > DATE_SUB(CAST('2020-05-07 16:20:00' AS DATETIME), INTERVAL 98 HOUR)

    WINDOW  w05 AS (PARTITION BY id ORDER BY dth RANGE INTERVAL '0:04' HOUR_MINUTE PRECEDING),
            w15 AS (PARTITION BY id ORDER BY dth RANGE INTERVAL '0:14' HOUR_MINUTE PRECEDING),
            w30 AS (PARTITION BY id ORDER BY dth RANGE INTERVAL '0:29' HOUR_MINUTE PRECEDING),
            w1 AS (PARTITION BY id ORDER BY dth RANGE INTERVAL '0:59' HOUR_MINUTE PRECEDING),
            w24 AS (PARTITION BY id ORDER BY dth RANGE INTERVAL '23:59' HOUR_MINUTE PRECEDING),
            w48 AS (PARTITION BY id ORDER BY dth RANGE INTERVAL '47:59' HOUR_MINUTE PRECEDING),
            w96 AS (PARTITION BY id ORDER BY dth RANGE INTERVAL '95:59' HOUR_MINUTE PRECEDING)
    ) subquery

# this HAVING clause returns only the rows I need _____________________________________________________________
HAVING subquery.dth >= DATE_SUB(CAST('2020-05-07 16:20:00' AS DATETIME), INTERVAL 2 HOUR);

Мой ТЕКУЩИЙ ЗАПРОС (см. Выше) работает, но на моей реальной производственной таблице он занимает очень много времени (до 10 секунд. Я хотел бы ускорить работу до чего-то вроде В 10 раз быстрее, по крайней мере).

Проблема с моим ТЕКУЩИЙ ЗАПРОС заключается в том, что он вычисляет эти суммы для всех строк за последние 98 часов ( WHERE pluv_reg.dth> DATE_SUB (CAST ('2020-05-07 16:20:00' AS DATETIME), ИНТЕРВАЛ 98 ЧАСОВ) ), хотя мне нужны только эти суммы за последние 2 часа ( HAVING subquery.dth> = DATE_SUB (CA ST ('2020-05-07 16:20:00' КАК ДАТА ВРЕМЯ), ИНТЕРВАЛ 2 ЧАСА) );

В приведенном ниже примере подзапрос создает 32 строки (40.000 на производстве). Предложение HAVING фильтрует его только до 20 строк (700 на производстве) - это единственные строки, которые мне нужны.

Операторы CREATE и INSERT:

CREATE TABLE pluv_reg (
id INT,
dth DATETIME,
valor DECIMAL(5,1),

PRIMARY KEY(id, dth)
);

INSERT INTO pluv_reg (id,dth,valor) VALUES
(1, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 0 MINUTE), 5),
(1, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 5 MINUTE), 5),
(1, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 10 MINUTE), 5),
(1, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 15 MINUTE), 5),
(1, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 20 MINUTE), 40),
(1, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 10 HOUR), 40),
(1, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 60 HOUR), 72),
(1, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 90 HOUR), 24),

(2, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 0 MINUTE), 5),
(2, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 5 MINUTE), 5),
(2, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 10 MINUTE), 5),
(2, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 15 MINUTE), 5),
(2, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 20 MINUTE), 40),
(2, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 10 HOUR), 40),
(2, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 60 HOUR), 72),
(2, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 90 HOUR), 24),

(3, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 0 MINUTE), 5),
(3, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 5 MINUTE), 5),
(3, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 10 MINUTE), 5),
(3, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 15 MINUTE), 5),
(3, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 20 MINUTE), 40),
(3, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 10 HOUR), 40),
(3, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 60 HOUR), 72),
(3, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 90 HOUR), 24),

(4, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 0 MINUTE), 5),
(4, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 5 MINUTE), 5),
(4, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 10 MINUTE), 5),
(4, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 15 MINUTE), 5),
(4, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 20 MINUTE), 40),
(4, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 10 HOUR), 40),
(4, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 60 HOUR), 72),
(4, (CAST('2020-05-07 16:20:00' AS DATETIME) - INTERVAL 90 HOUR), 24)
;
...