我想删除大量数据。这张表现在约有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);
}
}
此表数据显示给客户端查看,我担心如果删除出错会影响我的客户端。
我想知道有没有比我更好的方法。
如果你们需要我的更多信息,请告诉我。
谢谢
答案 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相同的方式处理查询,但没有:
答案 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的表逐行执行此操作。