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 查看每个查询中正在执行的操作。它将显示正在读取和连接的行数,以及正在使用的索引,帮助您缩小与未索引连接有关的任何问题。
我必须计算 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 查看每个查询中正在执行的操作。它将显示正在读取和连接的行数,以及正在使用的索引,帮助您缩小与未索引连接有关的任何问题。