【问题标题】:How to quickly prune large tables?如何快速修剪大表?
【发布时间】:2010-07-11 16:47:20
【问题描述】:

我目前有一个大约 2000 万行的 MySQL 表,我需要对其进行修剪。我想删除其updateTime(插入时间戳)超过一个月前的每一行。我没有亲自对表的顺序进行任何更改,因此数据应该按照插入的顺序,并且在两个字段idupdateTime 上有一个UNIQUE 键。我将如何在短时间内完成这项工作?

【问题讨论】:

    标签: mysql database pruning


    【解决方案1】:

    您可以承受多少停机时间?行有多大?你要删除多少?

    简单地说,删除行是您可以对表执行的最昂贵的操作之一。总的来说,这只是一件可怕的事情。

    如果您不必这样做,并且您有足够的磁盘空间,并且您的查询不受表大小的影响(索引良好的查询通常会忽略表大小),那么您可能会做得足够好一个人。

    如果您有机会并且可以使表格离线(并且您正在删除表格的很大一部分),那么您最好的选择是将要保留的行复制到新表格中,删除旧表格一,将新名称重命名为旧名称,然后重新创建索引。

    否则,您将几乎无法使用良好的 'ol delete。

    【讨论】:

      【解决方案2】:

      有两种方法可以删除大量行。首先是显而易见的方式:

      DELETE FROM table1 WHERE updateTime < NOW() - interval 1 month;
      

      第二种(稍微复杂一点)方法是创建一个新表并复制您要保留的数据,截断旧表,然后将行复制回来。

      CREATE TABLE table2 AS
      SELECT * FROM table1 WHERE updateTime >= NOW() - interval 1 month;
      
      TRUNCATE table1;
      
      INSERT INTO table1
      SELECT * FROM table2;
      

      当您有大量行要删除而要保留的行数相对较少时,使用TRUNCATE 比带有WHERE 子句的DELETE 快​​得多。

      【讨论】:

      • 我用一个有 370 万行的表进行了尝试。我不得不删除 200k 行。 TRUNCATE 方式更快。 (大约 10 分钟后,我厌倦了等待传统的 DELETE,而另一种方式大约需要 3 分钟)。我使用了一个 TEMPORARY 表
      • 好东西!减少备份+恢复时间的好方法
      【解决方案3】:

      使用限制拆分删除可能会加快进程;

      我不得不删除 10M 行并发出命令。它几个小时都没有回应。

      我终止了查询(花了几个小时)

      然后拆分删除。

      DELETE from table where id > XXXX limit 10000;
      DELETE from table where id > XXXX limit 10000;
      DELETE from table where id > XXXX limit 10000;
      DELETE from table where id > XXXX limit 10000;
      

      然后我在一个文件中复制了这个语句并使用了这个命令。

      mysql> source /tmp/delete.sql 
      

      这要快得多。

      您也可以尝试使用 pt-tools 等工具。和pt存档。

      【讨论】:

        【解决方案4】:

        其实即使你不能让表长时间离线,你仍然可以使用“重命名表”技术来摆脱旧数据。

        停止进程写入表。

        rename table tableName to tmpTableName;
        create table tableName like tmpTableName;
        set @currentId=(select max(id) from tmpTableName);
        set @currentId=@currentId+1;
        set @indexQuery = CONCAT("alter table test auto_increment = ", @currentId);
        prepare stmt from @indexQuery;
        execute stmt;
        deallocate prepare stmt;
        

        启动写入表的进程。

        insert into tableName
        select * from tmpTableName;
        drop table;
        

        对 tableName 的新插入将从正确的索引开始;旧数据将插入正确的索引中。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-06-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-10-04
          • 2019-06-30
          • 1970-01-01
          相关资源
          最近更新 更多