【发布时间】:2015-02-02 22:42:32
【问题描述】:
不确定处理此问题的最佳方法是什么。对于我的特殊情况,我有许多表,我想删除时间戳大于 3 个月前的任何行......也就是只保留过去 3 个月的记录。
很简单,就是这样:
//set binding cutoff timestamp
$binding = array(
'cutoff_time' => strtotime('-3 months')
);
//##run through all the logs and delete anything before the cutoff time
//app
$stmt = $db->prepare("
DELETE
FROM app_logs
WHERE app_logs.timestamp < :cutoff_time
");
$stmt->execute($binding);
//more tables after this
我要从中删除的每个表都有一个时间戳列,该列已编入索引。当要删除的行数很大时,我很担心。限制循环中的块的最佳做法是什么?我能想到的只是进行初始选择以查找是否有任何需要删除的行然后运行删除如果有...重复直到初始没有找到任何结果。这会为循环的每次迭代添加一个额外的计数查询。
这里的标准/推荐做法是什么?
编辑:
快速写下我的想法
//set binding cutoff timestamp
$binding = array(
'cutoff_time' => strtotime('-3 months')
);
//set limit value
$binding2 = array(
'limit' => 1000
);
//##run through all the logs and delete anything before the cutoff time
//get the total count
$stmt = $db->prepare("
SELECT
COUNT(*)
FROM app_logs
WHERE app_logs.timestamp < :cutoff_time
");
$stmt->execute($binding);
//get total results count from above
$found_count = $stmt->fetch(PDO::FETCH_COLUMN, 0);
// loop deletes
$stmt = $db->prepare("
DELETE
FROM app_logs
WHERE app_logs.timestamp < :cutoff_time
LIMIT :limit
");
while($found_count > 0)
{
$stmt->execute( array_merge($binding, $binding2) );
$found_count = $found_count - $binding2['limit'];
}
【问题讨论】:
-
最佳实践:在需要之前不要优化。您的方法可能在任何情况下都非常有效。当你有问题时解决问题。
-
执行
select来确定是否需要删除会使性能变得更糟。Delete已经做了自己的选择,看看是否需要删除。 -
@developerwjk - 完全正确,但是没有其他方法可以在不进行选择的情况下循环使用有限的删除查询。
-
@Hobo Sapiens - 我听到你在说什么,但在这种情况下,我宁愿一开始就把它敲掉,而不是让问题真正发生。由于我最多每天运行一次,因此以有限的方式处理这些问题的少数更改,即使需要,也几乎不会影响性能。
标签: php mysql delete-row sql-delete