逐行或批量删除

时间:2014-06-27 04:22:56

标签: php mysql performance delete-row

我想删除大量数据。这张表现在约有11207333

但是我有几种方法可以删除它。

将删除的数据大约为300k。我有两种方法可以做到这一点,但不确定哪一种方法表现得更快。

我的第一个选择:

$start_date     = "2011-05-01 00:00:00";
$end_date       = "2011-05-31 23:59:59";
$sql = "DELETE FROM table WHERE date>='$start_date' and date <='$end_date'";
$mysqli->query($sql);
printf("Affected rows (DELETE): %d\n", $mysqli->affected_rows);

第二个选项:

$query = "SELECT count(*) as count FROM table WHERE date>='$start_date' and date <='$end_date'";
$result = $mysqli->query($query);
$row = $result->fetch_array(MYSQLI_ASSOC);
$total = $row['count'];

if ($total > 0) {
    $query = "SELECT * FROM table WHERE date>='$start_date' and date <='$end_date' LIMIT 0,$total";
    $result = $mysqli->query($query);
      while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
            $table_id = $row['table_id']; // primary key
            $query = "DELETE FROM table where table_id = $table_id LIMIT 0,$total";
            $mysqli->query($query);

    }
}

此表数据显示给客户端查看,我担心如果删除出错会影响我的客户端。

我想知道有没有比我更好的方法。

如果你们需要我的更多信息,请告诉我。

谢谢

4 个答案:

答案 0 :(得分:0)

在我看来,第一种选择更快。

第二个选项包含循环,我认为它会慢一些,因为它会循环多次寻找你的表ID。

如果您没有提供错误的开始和结束日期,我认为您选择安全,但我认为选项1更快。

然后,我没有在选项2中看到任何删除,但我认为你已经记住它但使用循环方法。

答案 1 :(得分:0)

选项一是你最好的选择。

如果您害怕某些事情会“出错”,您可以先备份数据,导出您计划删除的行或实施逻辑删除标记来保护自己。

答案 2 :(得分:0)

假设其中确实存在DELETE查询,第二种方法不仅速度较慢,如果另一个连接删除了您要在while循环中删除的行之一,它可能会中断有机会这样做。要使它工作,您需要将其包装在事务中:

mysqli_query("START TRANSACTION;");
# your series of queries...
mysql_query("COMMIT;");

这将允许在隔离中正确处理您在db中发生的其他事件的查询。

无论如何,如果您希望第一个查询更快,则需要通过在用于删除的列上添加索引来调整表定义,即`date`(但是,请记住这个新索引如果该表上已有多个索引,可以在您的应用中安排其他查询。

如果没有该索引,mysql基本上会以与方法2相同的方式处理查询,但没有:

  • PHP解释,
  • 网络通讯和
  • 查询分析开销。

答案 3 :(得分:0)

您不需要任何SELECTS来循环删除。只需在删除查询中使用LIMIT并检查是否存在受影响的行:

$start_date     = "2011-05-01 00:00:00";
$end_date       = "2011-05-31 23:59:59";
$deletedRecords = 0;
$sql = "DELETE FROM table WHERE date>='$start_date' and date <='$end_date' LIMIT 100";
do {
$mysqli->query($sql);
$deletedRecords += $mysqli->affected_rows;
while ($mysqli->affected_rows > 0);
}

printf("Affected rows (DELETE): %d\n", $deletedRecords);

哪种方法更好取决于您使用的存储引擎。

如果您使用InnoDB,这是推荐的方法。原因是DELETE语句在一个事务中运行(即使在自动提交模式下,每个sql语句都在一个事务中运行,为了成为原子...如果它在中间失败,整个删除将被回滚并且你不会以半数据结束。这意味着你将有一个长时间运行的事务,并且在事务期间你将有很多锁定的行,这将阻止任何想要更新这些数据的人(如果涉及唯一索引,它可以阻止insterts)并且读取将是通过回滚日志完成。换句话说,对于InnoDB,如果以块的形式执行,则大删除会更快。

但是,在MyISAM中,删除会锁定整个表。如果你在很多小块中执行,你将执行太多的LOCK / UNLOCK命令,这实际上会减慢进程。我也会在MyISAM的循环中创建它,为其他进程提供使用该表的机会,但是与InnoDB相比在更大的块中。由于LOCK / UNLOCK开销,我永远不会为基于MyISAM的表逐行执行此操作。