我在使用Laravel的ORM Eloquent chunk()方法时遇到问题。 它错过了一些结果。 这是一个测试查询:
$destinataires = Destinataire::where('statut', '<', 3)
->where('tokenized_at', '<', $date_active)
->chunk($this->chunk, function ($destinataires) {
foreach($destinataires as $destinataire) {
$this->i++;
}
}
echo $this->i;
它给出了124838个结果。
但是:
$num_dest = Destinataire::where('statut', '<', 3)
->where('tokenized_at', '<', $date_active)
->count();
echo $num_dest;
给出了249676,所以只有TWICE作为第一个代码示例。
我的脚本应该编辑数据库中的所有匹配记录。如果我多次启动它,它每次只分发剩余记录的一半。
我尝试使用DB :: table()而不是Model。 我试图添加一个 - &gt; take(20000),但它似乎没有被考虑在内。 我用 - &gt; toSql()回复了查询,并且eveything似乎很好(当我添加 - &gt; take()参数时添加了LIMIT子句。)
有什么建议吗?
答案 0 :(得分:19)
想象一下,您正在使用chunk方法删除所有记录。该表有2,000,000条记录,您将删除所有这些记录1000个块。
$query->orderBy('id')->chunk(1000, function ($items) {
foreach($items as $item) {
$item->delete();
}
});
它将通过在查询中获取前1000条记录来删除前1000条记录,如下所示:
SELECT * FROM table ORDER BY id LIMIT 0,1000
然后来自chunk方法的另一个查询是:
SELECT * FROM table ORDER BY id LIMIT 1000,2000
我们的问题在于,我们删除1000条记录,然后从1000到2000获取结果。实际上我们缺少前1000条记录,这意味着我们不会在大块的第一步中删除1000条记录!其他步骤的情况也是如此。在每个步骤中,我们将错过1000条记录,这就是我们在这些情况下无法获得最佳结果的原因。
我做了一个删除示例,因为这样我们就可以知道chunk方法的确切行为。
<强>更新强>
您可以使用chunkById()
安全删除。
在这里阅读更多内容:
When to use single quotes, double quotes, and backticks in MySQL http://laravel.at.jeffsbox.eu/laravel-5-eloquent-builder-chunk-chunkbyid
答案 1 :(得分:8)
对于任何寻找解决此问题的代码的人,请转到:
while (Model::where('x', '>', 'y')->count() > 0)
{
Model::where('x', '>', 'y')->chunk(10, function ($models)
{
foreach ($models as $model)
{
$model->delete();
}
});
}
问题在于删除/移除模型,同时分析总数。将它包含在while循环中确保你得到它们!此示例适用于删除模型,更改while
条件以满足您的需求!
答案 2 :(得分:2)
我遇到了同样的问题 - 只有一半的总结果被传递给 chunk()方法的回调函数。
以下是有问题的代码:
Transaction::whereNull('processed')->chunk(100, function ($transactions) {
$transactions->each(function($transaction){
$transaction->process();
});
});
我使用Laravel 5.4并设法解决了用 cursor()方法替换 chunk()方法并相应更改代码的问题:
foreach (Transaction::whereNull('processed')->cursor() as $transaction) {
$transaction->process();
}
即使答案没有解决问题本身,它也提供了有价值的解决方案。