【问题标题】:Why do these sql queries take so long to execute为什么这些sql查询需要这么长时间才能执行
【发布时间】:2021-09-13 09:49:51
【问题描述】:

我有一个名为holdings_all 的表,它有超过 65m 行,每天都会在上面插入新行,其中一列是trade_type,它的值将取决于比较 SharesOwned 在今天的DateAdded-Fund-TickerDateAdded-Fund-Ticker 的前一天之间,可能的值是:

  • 如果今天的SharesOwned 等于前一天的SharesOwned 那么 Trade_Type = 0。
  • 如果今天的SharesOwned 小于前一天的SharesOwned 那么 Trade_Type = 1。
  • 如果今天的SharesOwned 大于前一天的SharesOwned 那么 Trade_Type = 2。
  • 如果今天的SharesOwned 在前一天不存在,那么 Trade_Type = 3。
  • 如果今天的SharesOwned 不存在但前一天存在,则 Trade_Type = 4。

为了让思考更快并避免行损坏,我采用了这种方法:

  • 在名为tmp_holdings_all 的表中下载新行。
  • 在名为 mlha 的表中从 holdings_all 获取前一天的行。
  • 最后,在tmp_holdings_all 中进行任何查询,然后将其移动到holdings_all 表中。

对于类型 0、1 和 2,我会在几秒钟内得到影响并纠正行,但是对于类型 3 和 4,它需要很长时间甚至超过几个小时并且永远不会完成,我在这里做错了什么?

UPDATE tmp_holdings_all uha
    JOIN (SELECT tha.id as cid, 
                CASE 
                    WHEN mlha.SharesOwned = tha.SharesOwned then 0
                    WHEN mlha.SharesOwned > tha.SharesOwned then 1
                    WHEN mlha.SharesOwned < tha.SharesOwned then 2
                END AS CTrade_type
            FROM mlha
            JOIN tmp_holdings_all tha
            ON tha.fund = mlha.fund 
            AND tha.ticker = mlha.ticker) ttha
    ON uha.id = ttha.cid
    SET uha.Trade_type = ttha.CTrade_type;

Trade_type 3 和 4:

UPDATE tmp_holdings_all uha
    JOIN (SELECT 
                ha.id as cid,
                CASE 
                    WHEN mlha.id IS NULL then 3
                END AS CTrade_type
            FROM mlha
                RIGHT JOIN tmp_holdings_all ha
                ON ha.fund = mlha.fund 
                AND ha.ticker = mlha.ticker
                where mlha.id IS NULL) ttha
    ON uha.id = ttha.cid
    SET 
        uha.Trade_type = ttha.CTrade_type;
    
REPLACE INTO tmp_holdings_all(Fund,ticker,SharesOwned, Trade_Type)
    SELECT 
        mlha.Fund, mlha.ticker, mlha.SharesOwned, 
        CASE 
            WHEN ha.id IS NULL then 4
        END AS Trade_type
    FROM mlha
        LEFT JOIN tmp_holdings_all ha
        ON ha.fund = mlha.fund 
        AND ha.ticker = mlha.ticker
        WHERE ha.id IS NULL

holding_all表结构:

CREATE TABLE IF NOT EXISTS `tmp_holdings_all` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
    `DateAdded` date DEFAULT NULL,
    `Fund` char(15) COLLATE utf8_bin DEFAULT NULL,
    `Asset` char(96) COLLATE utf8_bin DEFAULT NULL,
    `rank` int(11) DEFAULT NULL,
    `Weighting` float DEFAULT NULL,
    `Ticker` char(20) COLLATE utf8_bin DEFAULT NULL,
    `Style` char(15) COLLATE utf8_bin DEFAULT NULL,
    `FirstBought` date DEFAULT NULL,
    `SharesOwned` int(11) DEFAULT NULL,
    `Sector` char(45) COLLATE utf8_bin DEFAULT NULL,
    `Price` float DEFAULT NULL,
    `Country` char(25) COLLATE utf8_bin DEFAULT NULL,
    `Currency` char(3) COLLATE utf8_bin DEFAULT NULL,
    `PriceUSD` decimal(13,6) unsigned DEFAULT NULL,
    `Trade_type` int(11) DEFAULT NULL,
    PRIMARY KEY (`id`) ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1

【问题讨论】:

    标签: mysql left-join query-optimization


    【解决方案1】:

    如果它们是唯一的,请去掉 id 并将其添加到 mlhaha

    PRIMARY KEY(fund, ticker)
    

    如果不是mlha 可能需要INDEX(ticker, fund)

    一个“基金”是由许多“代码”组成的吗?

    我假设tmp_holdings_allholdings_all很多?在这种情况下,tha 中的索引可能并不重要;相反,它应该控制对大表的查找以进行更新。诀窍是确保它可以通过查找而不是表扫描来完成。

    使用VARCHAR,而不是CHAR,除非该列确实是固定长度的。

    tmp_holdings_all 中有什么内容?现有资产的更新?还是新持股?或两者(例如country)??对此的答案可能会导致执行多个查询而不是一个。否则可能会导致使用INSERT ... ON DUPLICATE KEY UPDATE。 (REPLACE 已过时,并分配了一个新的id。)

    您会更新所有 6500 万行吗?如果是这样,我预计需要数小时或数天。那时,我建议分块执行任务:http://mysql.rjweb.org/doc.php/deletebig#deleting_in_chunks

    holdings_all包含每日历史记录,对吗?您确实在跟踪 65M 行情。 (这听起来不切实际,所以我想了解什么是“持有”。也许包括“看跌”等?)

    【讨论】:

    • 一个“基金”是由许多“代码”组成的吗?是的,它可能有很多。当我使用mlha 进行连接时,我使用tmp_holdings_all 来惰性化新数据并更新它,它会更快,之后我将行移动到'holdings_all. ** The trick is to make sure it can do it with a lookup instead of a table scan** Can you explain more? **Will you be updating all 65M rows?** No, just the new rows that has been downloaded and inserted in tmp_holdings_all`。 holdings_all 不包含每日历史记录,对吗? 对,我正在跟踪每日,所以我必须每天重复该过程。
    • 执行UPDATEtmp_holdings_all 中有多少行?在 mlha 中?
    • 对每个查询分别计时;我怀疑REPLACE 需要更长的时间。
    • 我在前几段中添加了。
    • 抱歉,我的想法已经用完了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-31
    • 1970-01-01
    • 1970-01-01
    • 2011-08-27
    相关资源
    最近更新 更多