Php Laravel块和删除
我想从数据库中删除大量的项目(1M+),我会安排一个后台工作来处理,这样用户就不必等待它完成他/她正在做的任何事情,问题是,当项目被删除时,应用程序变得没有响应,所以我想我会一块一块地处理这些项目,然后睡上几秒钟,然后继续 以下是处理删除操作的代码:Php Laravel块和删除,php,laravel,eloquent,jobs,Php,Laravel,Eloquent,Jobs,我想从数据库中删除大量的项目(1M+),我会安排一个后台工作来处理,这样用户就不必等待它完成他/她正在做的任何事情,问题是,当项目被删除时,应用程序变得没有响应,所以我想我会一块一块地处理这些项目,然后睡上几秒钟,然后继续 以下是处理删除操作的代码: // laravel job class // ... public function handle() { $posts_archive = PostArchive::find(1); // just for the purpose of
// laravel job class
// ...
public function handle()
{
$posts_archive = PostArchive::find(1); // just for the purpose of testing ;)
Post::where('arch_id', $posts_archive->id)->chunk(1000, function ($posts) {
//go through the collection and delete every post.
foreach($posts as $post) {
$post->delete();
}
// throttle
sleep(2);
});
}
预期结果:将帖子分块并处理每个分块,然后空闲2秒,重复该操作直到删除所有项目
实际结果:删除一次随机数目的项目,然后过程结束。没有错误没有指标没有线索
有没有更好的方法来实现这一点?如果我理解正确,问题是删除大量条目需要太多资源。 一次写一篇文章会花费太长时间 尝试获取post.id的最小值和最大值,然后在类似的
for($i = $minId; $i <= $maxId-1000; $i+1000) {
Post::where('arch_id', $posts_archive->id)->whereBetween('id', [$i, $i+1000])->delete();
sleep(2);
}
for($i=$minId;$i id)->其中($id',[$i,$i+1000])->delete();
睡眠(2);
}
自定义数据块和睡眠时间,因为它适合您的服务器资源。如果我理解正确,问题是删除大量条目会占用太多资源。 一次写一篇文章会花费太长时间 尝试获取post.id的最小值和最大值,然后在类似的
for($i = $minId; $i <= $maxId-1000; $i+1000) {
Post::where('arch_id', $posts_archive->id)->whereBetween('id', [$i, $i+1000])->delete();
sleep(2);
}
for($i=$minId;$i id)->其中($id',[$i,$i+1000])->delete();
睡眠(2);
}
自定义区块和睡眠时间,因为它适合您的服务器资源。对于您处理此问题的方式,Laravel没有任何具体说明。如果作业中的删除查询冻结了UI的其余部分,则听起来您的数据库服务器需要检查或优化 检索每个模型并单独运行delete查询肯定不是优化此功能的好方法,因为您将执行数百万个查询。如果希望尝试限制应用程序中每秒的负载,而不是优化数据库服务器以处理此查询,则可以使用带有删除限制的while循环:
do {
$deleted = Post::where('arch_id', $posts_archive->id)->limit(1000)->delete();
sleep(2);
} while ($deleted > 0);
关于你处理这件事的方式,拉雷维尔没有什么特别的。如果作业中的删除查询冻结了UI的其余部分,则听起来您的数据库服务器需要检查或优化 检索每个模型并单独运行delete查询肯定不是优化此功能的好方法,因为您将执行数百万个查询。如果希望尝试限制应用程序中每秒的负载,而不是优化数据库服务器以处理此查询,则可以使用带有删除限制的while循环:
do {
$deleted = Post::where('arch_id', $posts_archive->id)->limit(1000)->delete();
sleep(2);
} while ($deleted > 0);
实际结果与预期结果不同的原因在于Laravel如何对数据集进行分块 Laravel一次分页一页数据集,并将
Post
模型的集合传递给回调函数
由于要删除集合中的记录,Laravel在每次迭代中都会跳过一页数据,因此最终会丢失原始查询中大约一半的数据
以下面的场景为例–您希望在10个区块中删除24条记录:
预期的
+-------------+--------------------+---------------------------+
| Iteration | Eloquent query | Rows returned to callback |
+-------------+--------------------+---------------------------+
| Iteration 1 | OFFSET 0 LIMIT 10 | 10 |
| Iteration 2 | OFFSET 10 LIMIT 10 | 10 |
| Iteration 3 | OFFSET 20 LIMIT 10 | 4 |
+-------------+--------------------+---------------------------+
注意:如果您只想删除数据库中的记录,这里的其他解决方案会更好。如果需要进行任何其他处理,则使用光标将是更好的选择。实际结果与预期结果不同的原因在于Laravel如何对数据集进行分块 Laravel一次分页一页数据集,并将
Post
模型的集合传递给回调函数
由于要删除集合中的记录,Laravel在每次迭代中都会跳过一页数据,因此最终会丢失原始查询中大约一半的数据
以下面的场景为例–您希望在10个区块中删除24条记录:
预期的
+-------------+--------------------+---------------------------+
| Iteration | Eloquent query | Rows returned to callback |
+-------------+--------------------+---------------------------+
| Iteration 1 | OFFSET 0 LIMIT 10 | 10 |
| Iteration 2 | OFFSET 10 LIMIT 10 | 10 |
| Iteration 3 | OFFSET 20 LIMIT 10 | 4 |
+-------------+--------------------+---------------------------+
注意:如果您只想删除数据库中的记录,这里的其他解决方案会更好。如果您需要进行任何其他处理,那么使用光标将是一个更好的选择。正如Kelvin Jones指出的,删除随机数项的原因是您在翻页时删除了记录
chunk
只需使用offset和limit在表中“分页”。但是,如果您从第1页(IDs1-100)删除100条记录,然后转到第2页,实际上您现在跳过了IDs101-200并跳到了201-300
chunkById
是解决这个问题的一种方法
Post::where('arch\u id',$posts\u archive->id)->chunkById(1000,函数($posts){
//浏览收集并删除所有帖子。
foreach($posts作为$post){
$post->delete();
}
});
从字面上讲,只需替换方法名即可。现在,它不再使用offset&limit进行分页,而是从第一页查看最大主键(100),然后下一页将查询
其中ID>100
。因此,第2页现在正确地为您提供了ID 101-200,而不是201-300。正如开尔文·琼斯所指出的,删除随机数项的原因是,您在翻页时删除了记录
chunk
只需使用offset和limit在表中“分页”。但是,如果您从第1页(IDs1-100)删除100条记录,然后转到第2页,实际上您现在跳过了IDs101-200并跳到了201-300
chunkById
是解决这个问题的一种方法
Post::where('arch\u id',$posts\u archive->id)->chunkById(1000,函数($posts){
//浏览收集并删除所有帖子。
foreach($posts作为$post){
$post->delete();
}
});
从字面上说,只需更换