我创建了一个mysql查询,通过使用多个自联接来计算数据的移动平均值,如下所示。这很耗时,每个查询的数据行数为10万。有什么方法可以进一步优化以减少时间吗?
select a.rownum,a.ma_small_price, b.ma_medium_price from
(SELECT t3.rownum, AVG(t.last_price) as 'ma_small_price'
FROM temp_data t3
left JOIN temp_data t ON t.rownum BETWEEN ifnull(t3.rownum,0) - @psmall AND t3.rownum
GROUP BY t3.rownum)
inner join
(SELECT t3.rownum, AVG(t.last_price) as 'ma_medium_price'
FROM temp_data t3
left JOIN temp_data t ON t.rownum BETWEEN ifnull(t3.rownum,0) - @pmedium AND t3.rownum
GROUP BY t3.rownum) b on a.rownum = b.rownum
由于您正在运行MySQL 8,因此您应该能够使用窗口函数来更有效地获得相同的结果。没有看到样本数据,很难100%确定,但这应该很接近。请注意,要在窗口框架中使用变量,您需要使用准备好的语句:
SET @sql = '
SELECT rownum,
AVG(last_price) OVER (ORDER BY rownum ROWS BETWEEN ? PRECEDING AND CURRENT ROW) AS ma_small_price,
AVG(last_price) OVER (ORDER BY rownum ROWS BETWEEN ? PRECEDING AND CURRENT ROW) AS ma_medium_price
FROM temp_data';
PREPARE stmt FROM @sql;
EXECUTE stmt USING @psmall, @pmedium;
OVER ( ... )
令人失望地慢-在MySQL 8.0和MariaDB 10.x中。
我喜欢“指数移动平均线”比“移动平均线”更易于计算。以下内容大致相当于尼克提出的内容。这运行得更快,但结果略有不同:
SELECT rownum,
@small := @small + 0.5 * (last_price - @small) AS mae_small_price,
@med := @med + 0.2 * (last_price - @med) AS mae_med_price
FROM ( SELECT @small := 10, @med := 10 ) AS init
JOIN temp_data
ORDER BY rownum;
系数控制指数移动平均值适应数据变化的速度。它应大于0且小于1。