Временные ряды MySQL взвешивали среднее значение, используя оконные функции - PullRequest
1 голос
/ 18 марта 2019

У меня есть простая таблица data для данных временных рядов, в основном только отметка времени и значение:

Field, Type, Null, Key, Default, Extra
'id','int(11)','NO','PRI',NULL,'auto_increment'
'channel_id','int(11)','YES','MUL',NULL,''
'timestamp','bigint(20)','NO','',NULL,''
'value','double','NO','',NULL,''

Я разработал несколько сложный запрос для расчета средневзвешенного значения по периодам, в основном вычисляя sum(val x delta time). Переменная @prev_timestamp в основном имитирует функцию LAG(). Пример:

SELECT 
    MAX(agg.timestamp) AS timestamp, 
    COALESCE( 
        SUM(agg.val_by_time) / (MAX(agg.timestamp) - MIN(agg.prev_timestamp)), 
        AVG(agg.value)
    ) AS value
FROM ( 
    SELECT 
        timestamp, 
        value, 
        value * (timestamp - @prev_timestamp) AS val_by_time, 
        COALESCE(@prev_timestamp, 0) AS prev_timestamp, 
        @prev_timestamp := timestamp 
    FROM data 
    CROSS JOIN (
        SELECT @prev_timestamp := NULL
    ) AS vars 
    WHERE channel_id=56  AND timestamp >= 1546297161097 AND timestamp <= 1552950000000 
    ORDER BY timestamp ASC
) AS agg 
GROUP BY (timestamp - 1546288811393) >> 23 
ORDER BY timestamp ASC
;

Недавно я преобразовал этот запрос из хакерского подхода к переменным MySQL для использования оконных функций:

SELECT 
    MAX(agg.timestamp) AS timestamp, 
    COALESCE(
        SUM(agg.val_by_time) / (MAX(agg.timestamp) - MIN(agg.prev_timestamp)), 
        AVG(agg.value)
    ) AS value
FROM ( 
    SELECT 
        timestamp, 
        value, 
        LAG(timestamp) OVER(ORDER BY channel_id, timestamp ASC) AS prev_timestamp,
        value * (timestamp - LAG(timestamp) OVER(ORDER BY channel_id,timestamp ASC)) AS val_by_time
    FROM data 
    WHERE channel_id=56  
    AND timestamp >= 1546297161097 AND timestamp <= 1552950000000 
    ORDER BY timestamp ASC

) AS agg 
GROUP BY (timestamp - 1546288811393) >> 23 
ORDER BY timestamp ASC
;

Недостатком является то, что версия, использующая оконные функции - хотя, по-видимому, чище - работает примерно на 25% медленнее (MariaDB 10.3, Raspi 3).

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

...