mysql中的多个移动平均线

时间:2018-09-30 05:43:21

标签: mysql moving-average

我必须在mysql数据集中计算移动平均值(不同周期)。我尝试了两种方法来计算平均值,但是两者都花费了大量时间。分享下面的代码。

方法:-1

select t1.*, 
    (select avg(t2.last_price) 
        from temp_data t2 
        where t2.rownum>t1.rownum-50 and t2.rownum<=t1.rownum and t1.script_code=t2.script_code) as 'ma_small_price'
from temp_data t1;

方法:-2

select t1.*, avg(t2.last_price) 'ma_small_price'
from temp_data t1
join temp_data t2
where t2.rownum>t1.rownum-50 and t2.rownum<=t1.rownum and t1.script_code=t2.script_code
group by t1.id,t1.date, t1.time;

这是表结构:

  CREATE TABLE `temp_data` (
  `id` int(11) NOT NULL DEFAULT '0',
  `rownum` int(11) DEFAULT NULL,
  `script_code` float DEFAULT NULL,
  `date` date DEFAULT NULL,
  `time` time DEFAULT NULL,
  `last_price` float DEFAULT NULL,
  `last_qty` float DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

rownum是具有连续行号的列。 ID是主键,但不是连续键,因此我必须添加一个单独的列

示例数据链接:https://www.dropbox.com/s/z8iacqvlkjdx6ax/temp_data_sample.xlsx?dl=0

接下来,我必须对同一数据平行计算多个移动平均值,但是周期(在上面的代码中指定为50)不同。

我的数据集非常庞大且正在增长(> 100万行),并且运行这些查询所花费的时间非常长-每个〜20分钟。寻求有关如何改进这些查询以减少运行时间的投入。谢谢!

2 个答案:

答案 0 :(得分:1)

好问题 挑战在于对每行的迭代进行分组以进行跳转 因此,我们需要定义一个开始时间段和一个结束时间段,并在这些时间段之间连接同一张表

由于表格的大小,我添加了按和限制的订单

我还将索引添加到rownum列,以使连接和组运行更快

希望有帮助

ALTER TABLE temp_data ADD key rownum (rownum) ;


    SELECT 
         t3.rownum AS endp, 
        AVG(t3.last_price)
        FROM
temp_data t3
INNER JOIN temp_data t ON t.rownum BETWEEN  MAX(IFNULL(t3.rownum, 0)) - 50 AND t3.endp
        GROUP BY
        endp
ORDER BY rownum DESC
LIMIT 0,1000

答案 1 :(得分:0)

好的。首先,只有1M行,这不需要20分钟。更像是20秒。如果您的rownum列是唯一的,则应将其索引为唯一键。它也应该是一个无符号的int。这样做会大大减少查询时间,因为现在看来您正在为每个联接进行完整的未排序表扫描。

第二,除非有某些原因对于比较大量历史数据的数据库不明显,否则应使用ISAM表,而不是InnoDB。

第三,必须对script_code建立索引,否则您将进行全表扫描。

更多: *方法2中的join语句是将每一行连接到每一行,然后执行where。您应该在rownum> t1.rownum-50和rownum <= t1.rownum上左联接,而不是执行常规联接然后运行where。即使没有索引rownum,这也将大大加快查询速度。 *如果希望获得更多数据,则还应考虑根据rownum对表进行分区。分区对于加速此类读取非常有用,因为您正在访问的大多数数据都是顺序的,并且将落在一个或两个分区内,因此可以加快读取速度。对于您的情况,您还可以按日期进行分区,这对于其他操作可能很方便。 *查看EXPLAIN SELECT并查看联接上正在使用的键。考虑使用USE INDEX提示以使用rownum代替联接的主键。

看来,您自己的查询似乎都不正确。完成上述优化后,我的猜测是您的方法1(子查询)将比没有方法2中的WHERE的正确JOIN ON更快。

那时候,您应该使用EXPLAIN SELECT来查看每个查询中正在执行的操作。它将显示正在读取和联接的行数以及正在使用的索引,从而帮助您缩小未索引联接的所有问题。