【问题标题】:MySql how to speed-up working query with window functionsMySql如何使用窗口函数加速工作查询
【发布时间】:2021-09-04 16:25:49
【问题描述】:

编辑:实际上,主要问题是上次更新设置 A.last_52w_high_age_brutto_days(见下文)。是否可以优化此更新或以某种方式集成到 CURSOR 更新中?谢谢。


我有一张包含股市每日价格的表格。

表结构:

CREATE TABLE `cind_stocks_daily_rates` (
  `symbol` varchar(12) NOT NULL,
  `p_date` int unsigned NOT NULL,
  `open_price` decimal(9,4) NOT NULL,
  `high_price` decimal(9,4) NOT NULL,
  `low_price` decimal(9,4) NOT NULL,
  `close_price` decimal(9,4) NOT NULL,
  `price_52w_low` decimal(9,4) DEFAULT NULL,
  `price_52w_high` decimal(9,4) DEFAULT NULL,
  `last_52w_high_age_brutto_days` int unsigned DEFAULT NULL,
  PRIMARY KEY (`symbol`,`p_date `)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT 语句:

INSERT INTO cind_stocks_daily_rates (symbol, datum, open_price, high_price, low_price, close_price, price_52w_low, price_52w_high, last_52w_high_age_brutto_days)
VALUES
('DELL', 20210616, 150, 152, 149, 151, 149, 152, 0),
('INTZ', 20210616, 250, 252, 249, 251, 249, 252, 0),
('MSFT', 20210616, 350, 352, 349, 351, 349, 352, 0),
('NTNX', 20210616, 452, 452, 449, 451, 449, 452, 0),
('DELL', 20210617, 148, 151, 147, 150, 147, 152, 1),
('INTZ', 20210617, 251, 254, 250, 252, 249, 254, 0),
('MSFT', 20210617, 346, 349, 345, 347, 345, 352, 1),
('NTNX', 20210617, 450, 454, 450, 453, 449, 454, 0),
('DELL', 20210618, 146, 147, 144, 145, NULL, NULL, NULL),
('INTZ', 20210618, 254, 256, 253, 255, NULL, NULL, NULL),
('MSFT', 20210618, 349, 351, 349, 350, NULL, NULL, NULL),
('NTNX', 20210618, 453, 456, 452, 454, NULL, NULL, NULL);

想要的结果:

symbol  datum   open_price  high_price  low_price   close_price price_52w_low   price_52w_high  last_52w_high_age_brutto_days
DELL    20210616    150 152 149 151 149 152 0
INTZ    20210616    250 252 249 251 249 252 0
MSFT    20210616    350 352 349 351 349 352 0
NTNX    20210616    452 452 449 451 449 452 0
DELL    20210617    148 151 147 150 147 152 1
INTZ    20210617    251 254 250 252 249 254 0
MSFT    20210617    346 349 345 347 345 352 1
NTNX    20210617    450 454 450 453 449 454 0
DELL    20210618    146 147 144 145 144 152 2
INTZ    20210618    254 256 253 255 249 256 0
MSFT    20210618    349 351 349 350 345 352 2
NTNX    20210618    453 456 452 454 449 456 0

在表格中填写给定日期的价格/费率后,我想计算过去 52 周的高价和低价 - 以及过去 52 周高价和价值日期列。

我创建了一个光标:

SELECT distinct symbol FROM cind_stocks_daily_rates
WHERE  price_52w_low IS NULL OR price_52w_high IS NULL;

并通过光标(curr_symbol)循环符号:

UPDATE cind_stocks_daily_rates AS A
CROSS JOIN
(SELECT AA.p_date, AA.symbol,
Min(AA.low_price) OVER (ORDER BY AA.p_date ROWS BETWEEN 260 PRECEDING AND CURRENT ROW) AS low_price_52w,
Max(AA.high_price) OVER (ORDER BY AA.p_date ROWS BETWEEN 260 PRECEDING AND 
CURRENT ROW) AS high_price_52w
FROM cind_stocks_daily_rates AA
WHERE AA.symbol = curr_symbol
ORDER BY AA.p_date) as B ON B.symbol = A.symbol AND B.p_date = A.p_date
SET A.price_52w_low = B.low_price_52w,
A.price_52w_high = B.high_price_52w,
WHERE  A.price_52w_low IS NULL OR A.price_52w_high IS NULL;

在光标循环之后,我有另一个更新来确定从今天开始的当前 52 周高价有多长:

编辑:实际上,以下更新是我的主要问题(也是唯一的问题)。持续时间约+/- 10 分钟。 END_OF_EDIT

UPDATE cind_stocks_daily_rates AS A
CROSS JOIN
 (SELECT AA.p_date, AA.symbol,
DATEDIFF(STR_TO_DATE(AA.p_date, "%Y %m %d"),STR_TO_DATE(
    (SELECT CCC.p_date
    FROM cind_stocks_daily_rates CCC
    WHERE CCC.symbol = AA.symbol AND CCC.p_date <= AA.p_date AND CCC.high_price = AA.price_52w_high ORDER BY CCC.p_date DESC LIMIT 1)
    , "%Y %m %d")) AS last_high_Date
    FROM cind_stocks_daily_rates AA) as B ON B.symbol = A.symbol AND B.p_date = A.p_date
        SET A.last_52w_high_age_brutto_days = B.last_high_Date
WHERE A.last_52w_high_age_brutto_days IS NULL;

它可以按需要进行所有操作而不会出错,只是需要花费太多时间。有没有可能加快速度?是否可以在游标内一起设置字段“last_52w_high_age_brutto_days”(游标循环后没有第二次更新)?请问有什么想法可以加快查询速度吗?

【问题讨论】:

  • 多少时间才算太多?
  • 为什么要跨界加入?
  • Besidaes 所有的 STR_:TO_DATE 都必须计时并且您多次执行,为什么不保存它们正确的 mysql 样式并摆脱所有 taht
  • Edit 问题并完成minimal reproducible example,即为示例数据提供INSERT 语句(粘贴文本,不要使用图像,不要链接到外部网站)和表格文本格式的样本数据的期望结果。
  • "And loop ... through the Cursor" -- 这是您要摆脱的第一件事。 RDBMS 擅长基于集合的操作,但在循环游标方面很糟糕。

标签: mysql window-functions cross-join cursors


【解决方案1】:

让我们尽量避免每天都做所有事情。

一项艰巨的任务是找到 52 周的最高价格。看看有没有捷径。

维护一个单独的表格,每个股票一行,记录 52 周高点和日期。

如果 52 周高点的日期(对于给定的股票代码)小于 52 周前,则不重新计算价格和日期。

然后可以轻松快速地发现哪些代码(如果有)需要重新计算其高点。更新此表。然后使用此表填充您要询问的表;这个UPDATE...JOIN... 会很高效。

一些潜在的问题--

  • 非交易日:我不认为,这完全搞乱了查询;忽略它。
  • 有时,大多数代码会在 52 周前达到最高点:这种情况很少见,而且很慢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-16
    • 2014-03-10
    • 1970-01-01
    • 1970-01-01
    • 2015-11-22
    • 1970-01-01
    • 2011-11-23
    • 1970-01-01
    相关资源
    最近更新 更多