【问题标题】:multiple moving averages in mysqlmysql中的多个移动平均线
【发布时间】:2019-03-05 14:42:29
【问题描述】:

我必须在 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)是不同的。

我的数据集庞大且不断增长(> 1 百万行),运行这些查询所需的时间很长 - 每个约 20 分钟。寻求有关如何改进这些查询以减少运行时间的输入。谢谢!!

【问题讨论】:

  • 这看起来很像 Oracle 代码。你确定你使用的是 MySQL 吗?
  • 是的,我确定......在我的机器上托管的 mysql 服务器中使用它们
  • 请发布一些表结构和示例数据。看起来rownum 实际上是一个列名。
  • 我已经添加了表结构。 rownum 是具有连续行号的列。 ID 是主键,但不是连续的,所以我不得不添加一个单独的列。不确定如何为数据添加示例附件。我怎样才能把它贴在这里?
  • 您没有索引。最重要的是,这就是扼杀性能的原因。

标签: mysql moving-average


【解决方案1】:

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

由于表格的大小,我添加了 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

【讨论】:

  • 你确定这样更快吗?
  • 我需要放开子查询并添加适当的限制...我还想扩展关于索引的答案
  • 去掉多余的rownum列也不错
  • 坦率地说,将整个内容复制到一个以 rownum 作为主键的新表中会比任何一个都快得多,但最糟糕的是初始查询中的无限制连接......这个如果日期被索引,应该更快,但它可能会通过将数据分块到日期期间来创建工件或不一致。
  • 这很好用。仅加入数据集的一部分即可。这大大减少了运行时间。谢谢!!
【解决方案2】:

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

其次,除非出于某种原因对于比较大量历史数据的数据库而言并不明显,否则您应该使用 ISAM 表,而不是 InnoDB。

第三,script_code 必须被索引,否则你将进行全表扫描。

更多: * 您在方法 2 中的连接语句是将每一行连接到每一行,然后执行 where。您应该在 rownum>t1.rownum-50 AND rownum

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

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

【讨论】:

  • 十年前,关于 MyISAM 与 InnoDB 的老观点可能有些道理,但现在不是了。此外,参照完整性胜过任何(微小的,我怀疑不存在的)潜在性能优势
  • 完全披露,十年前我几乎用 InnoDB 做所有事情。实际上,只有很多关于大型表上的锁会导致大型数据库崩溃的极端情况让我确信,使用完全简短的写锁和 MyISAM 比使用行级锁定更好。这些年来,我的直觉是 MyISAM 的大连接速度更快,但又一次来自几乎总是有一些写入试图同时发生的环境,所以也许是只读环境中的速度差异可以忽略不计。问题是,如果你不需要它,为什么要使用它?
猜你喜欢
  • 2011-06-29
  • 1970-01-01
  • 1970-01-01
  • 2017-09-01
  • 2013-12-22
  • 1970-01-01
  • 2019-07-13
  • 2021-04-19
  • 2022-01-26
相关资源
最近更新 更多