【问题标题】:Mysql delete and optimize very slowmysql删除优化很慢
【发布时间】:2014-01-09 17:37:39
【问题描述】:

我在 Internet 和 Stack Overflow 上搜索了我的问题,但找不到好的解决方案。

我有一个包含 300,000 行的表 (MySql MyISAM)(一列是 blob 字段)。

我必须使用:

DELETE FROM tablename WHERE id IN (1,4,7,88,568,.......)

IN 语法中有近 30,000 个 id。

大约需要 1 小时。此外,虽然我删除了 10% 的 .MYD 文件,但它并没有使文件变小,所以我运行 OPTIMIZE TABLE... 命令。它也持续很长时间......(我应该使用它,因为磁盘空间对我来说很重要)。

如上删除数据并恢复空间时,有什么方法可以提高性能? (增加缓冲区大小?哪个?还是其他?)

【问题讨论】:

  • 最好将这些 ID 填充到临时表中,然后执行删除/连接查询。
  • 与查询一起使用基本上会强制检查每行被删除的每个值。在删除实际运行之前,您可能会扫描 30,000 个 ID。
  • @MarcBs 和 @user2366842s cmets 是正确的。创建一个包含所有 ID 的临时表,然后 delete from tablename where id in (select id from temporarytable) 可能有助于优化器提高速度。此外,考虑在删除之前删除索引(id 上的索引除外!)并在删除后重建它们可能比让删除不断更改它们更快。
  • 另一个选项(不确定这有多可行,取决于您总共有多少记录)是如果表没有外键约束,您可以复制 ISN'T 中的所有内容将列表复制到临时表,在原始表上运行截断,然后将剩余的所有内容复制回来(假设这是一次性删除作业,而不是定期运行的东西)

标签: mysql optimization sql-delete


【解决方案1】:

使用IN,MySQL 将扫描表中的所有行并将记录与IN 子句匹配。 IN 谓词列表将被排序,数据库中的所有 300,000 行将针对 30,000 个 id 进行二分搜索。

如果您在临时表上使用 JOIN 执行此操作(临时表上没有索引),假设 id 已编入索引,则数据库将对 300,000 条记录索引执行 30,000 次二进制查找。

那么,对 30,000 条记录进行 300,000 次二进制搜索,或对 300,000 条记录进行 30,000 次二进制搜索...哪个更快?到目前为止,第二个更快。

此外,使用DELETE QUICK 延迟索引重建将导致更快的删除。数据文件和索引中的所有记录都将被简单地标记为已删除,并且不会重建索引。

然后,要恢复空间并稍后重建索引,请运行 OPTIMIZE TABLE

【讨论】:

    【解决方案2】:

    IN() 语句中的 size of the list 可能是原因。您可以将 ID 添加到临时表并加入以执行删除。此外,当您使用 MyISAM 时,您可以使用 DELETE QUICK 选项来避免删除时索引命中:

    对于 MyISAM 表,如果使用 QUICK 关键字,存储引擎 在删除过程中不合并索引叶子,这可能会加快一些 各种删除操作。

    【讨论】:

      【解决方案3】:

      我认为使其更快的最佳方法是创建一个新表并将您不想删除的行插入其中,然后删除原始表,然后您可以将表中的内容复制到主表.

      类似这样的:

      INSERT INTO NewTable SELECT * FROM My_Table WHERE ... ;
      

      然后你可以使用 RENAME TABLE 将副本重命名为原始名称

      RENAME TABLE My_Table TO My_Table_old, NewTable TO My_Table ;
      

      然后最后删除原表

      DROP TABLE My_Table_old;
      

      【讨论】:

      • 这将有助于获得一个较小的文件,但他在创建新文件时需要两个文件的空间,而他可能没有那个空间。
      • OP 只删除了 10% 的记录。我不认为这种方法会更快。
      【解决方案4】:

      试试这个

      1. 使用单列 id 创建表名 temptable
      2. 插入表1,4,7,88,568,......
      3. 使用删除加入类似的东西
      4. DELETE ab, b FROM originaltable AS a INNER JOIN temptable AS b ON a.id= b.id where b.id is null;

      这只是一个想法。该查询未经测试。你可以在谷歌上检查语法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-06
        • 2010-12-31
        • 1970-01-01
        • 2020-05-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多