mysql 中的多个移动平均线

multiple moving averages in mysql

我必须计算 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;

这是table结构:

  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 是主键但不是连续的所以我不得不添加一个单独的列

Link 样本数据:https://www.dropbox.com/s/z8iacqvlkjdx6ax/temp_data_sample.xlsx?dl=0

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

我的数据集庞大且不断增长(> 100 万行),这些查询 运行 花费的时间很长 - 每次约 20 分钟。寻求有关如何改进这些查询以减少 运行 时间的意见。谢谢!!

好问题 挑战是通过迭代对每一行进行分组 所以我们需要定义一个开始时间段和一个结束时间段,并在这些时间段之间加入相同的table

由于 table

的大小,我添加了 order by 和 limit

我还会将索引添加到 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

好的。首先,只有 1M 行,这不应该花费 20 分钟。更像是20秒。如果你的 rownum 列是唯一的,它应该被索引为一个唯一的键。它也应该是一个无符号整数。做这些事情会大大减少您的查询时间,因为现在您似乎正在对每个连接进行完全未排序的 table 扫描。

其次,除非有一些对于比较大量历史数据的数据库来说不明显的原因,否则您应该使用 ISAM table,而不是 InnoDB。

第三,script_code 必须被索引,否则您将进行完整的 table 扫描。

更多: * 方法 2 中的连接语句将每一行连接到每一行,然后执行 where。您应该 LEFT JOIN ON rownum>t1.rownum-50 AND rownum<=t1.rownum,而不是先进行常规联接,然后 运行 where。即使没有索引 rownum,这也会显着加快查询速度。 * 如果您希望获得更多数据,您还应该考虑根据 rownum 对 table 进行分区。分区非常适合加速这些类型的读取,其中您访问的大部分数据都是顺序的,并且将落在一个或两个分区中。在您的情况下,您还可以按日期分区,这可能对其他操作很方便。 * 查看 EXPLAIN SELECT 并查看在连接上使用了哪些键。考虑使用 INDEX 提示使用 rownum 而不是连接的主键。

您的查询本身似乎都没有错。完成上述优化后,我的猜测是您的方法 1(子查询)仍然比方法 2 中没有 WHERE 的正确 JOIN ON 更快。

此时,您应该使用 EXPLAIN SELECT 查看每个查询中正在执行的操作。它将显示正在读取和连接的行数,以及正在使用的索引,帮助您缩小与未索引连接有关的任何问题。