MySQL DELETE 因大量行而变得异常缓慢

Cra*_*obs 7 mysql trigger performance delete query-performance

对 Prices 表中的大量行执行 DELETE 时,DELETE 会逐渐变慢。如果删除 15,000 行,它会在大约 15 秒内运行。20K 行需要 3 或 4 分钟。40,000 行需要 15 分钟,100,000 行运行一个多小时。

下面的 After DELETE 触发器使用可用价格类型的计数更新 Items 表。这用于计算价格以加快生产过程。

两个表都是InnoDB,我把innodb_buffer_pool_size更新为4G,没有效果。

我已经验证所有 SQL 语句都使用索引。Prices 表上有一个PriceType + ItemID 索引,ItemID 是Items 表的主键。

不幸的是,这个架构是由另一个应用程序确定的,我无法修改表结构。我可以修改触发器、索引等。无法更改该应用程序以直接更新 Items 表中的计数。

BEGIN

    DECLARE iPriceTypeA INT;
    DECLARE iPriceTypeB INT;
    DECLARE iPriceTypeC INT;

    SET iPriceTypeA = (SELECT COUNT(*) FROM Prices WHERE PriceType='A' AND ItemID=OLD.ItemID),
        iPriceTypeB = (SELECT COUNT(*) FROM Prices WHERE PriceType='B' AND ItemID=OLD.ItemID),
        iPriceTypeC = (SELECT COUNT(*) FROM Prices WHERE PriceType='C' AND ItemID=OLD.ItemID);

    UPDATE Items 
        SET PriceTypeA = iPriceTypeA,
            PriceTypeB = iPriceTypeB,
            PriceTypeC = iPriceTypeC,
        WHERE ItemID = OLD.ItemID;

END
Run Code Online (Sandbox Code Playgroud)

这似乎不应该造成问题,但是当删除 120K 行时,服务器会在几个小时内无法使用。为什么这个查询会随着行数的增加而呈指数级增长?

编辑:使用价格表架构更新

ItemCode varchar(30)
PriceType char(1)
Method char(1)
Factor decimal(7,2)
Run Code Online (Sandbox Code Playgroud)

编辑:

我仍然不明白为什么这个触发器会导致删除随着记录数量的增加而变慢。正如我所说,如果我删除触发器调用,删除非常快。我真的很想深入了解性能问题。

为了让事情现在正常工作,我的解决方案是切换到 MyISAM,因为该表仅用于我们应用程序中的选择。

Ric*_*mes 12

使用 InnoDB,必须保留已删除的行,以防发生崩溃或其他原因回滚操作。如您所见,这是成本高昂的,并且可能会随着数量的增加而变得更加昂贵。

计划 A:在较小的块中和COMMIT在每个块之后删除。(同样,分块应该应用于更新。)

计划 B、C、D、... 查看更多提示

如果没有 WHERE

没有WHERE?最好创建一个新表,然后使用RENAME TABLE原子将新表交换到位。并以DROP TABLE. 没有停机时间;没有昂贵的删除。

查询重写

如果您运行的是 5.7,则有一项新功能可让您“重写”查询以适应各种麻烦。 更多讨论。您可能可以将没有 where 的 delete 变成DROPand CREATE。(这不如之前的建议好。)