2016-08-19 6 views
3

私は非常に大きな結果セットを処理するので、ジョブのメモリフットプリントを減らすにはchunk()メソッドを使用しています。ただし、ジョブが長時間実行されないように、特定の数の合計結果を処理したいだけです。奇妙なチャンクを制限する

現在、私はこれをやっているが、それはエレガントな解決策のように見えるしていません:

$count = 0; 
$max = 1000000; 
$lists = Lists::whereReady(true); 

$lists->chunk(1000, function (Collection $lists) use (&$count, $max) { 
    if ($count >= $max) 
     return; 

    foreach ($lists as $list) { 
     if ($count >= $max) 
      break; 

     $count++; 

     // ...do stuff 
    } 
}); 

これを行うにはクリーンな方法はありますか?

+0

@whoanこれは、 'chunk'が' limit'の仮名である 'take'を使う' forPage'を呼び出しているために動作しません。そのため、 'chunk'はあなたが' limit'に渡したものを上書きします。 – eComEvo

+0

私はコレクションオブジェクトのtake関数を見たと思います。役に立たない入力のために申し訳ありません。 – Gokigooooks

答えて

1

今のところ、私はそう信じていません。

チャンクを以前に設定したスキップ/リミットを尊重するために提出されたいくつかの問題とプル要求がありましたが、Taylorはそれらをチャンクが上書きする予想される動作として閉じました。

laravel/internalsリポジトリには現在open issueがあります。彼は再度見てみると言っていましたが、優先順位リストでは高くないと思います。私はそれが彼が仕事をするだろうとは思っていませんが、今度は別のプルのリクエストを受け入れるかもしれません。

あなたの解決策は、1つのことを除いて、うまく見えます。 chunk()は、あなたがクロージャーからfalseを返さない限り、テーブル全体を読むことになります。現在、nullを返しているだけなので、 "max"が1000000に設定されていても、テーブル全体が読み込まれます。 $count >= $maxの場合、return falseが閉鎖されている場合、chunk()はデータベースのクエリを停止します。 chunk()はそれ自体falseを返すでしょうが、あなたのサンプルコードは、とにかくchunk()の返品を気にしないので、大丈夫です。


別のオプションは、あなたがシーケンシャルのIDを使用していると仮定すると、idエンディングを取得することで、その後、あなたの最大idよりid少ないとすべてのレコードを取得するために、あなたのチャンククエリにwhere句を追加します。だから、何かのように:

$max = 1000000; 
$maxId = Lists::whereReady(true)->skip($max)->take(1)->value('id'); 

$lists = Lists::whereReady(true)->where('id', '<', $maxId); 

$lists->chunk(1000, function (Collection $lists) { 
    foreach ($lists as $list) { 
     // ...do stuff 
    } 
}); 

コードは少しクリーナーですが、それはまだハックです、そして(最大IDを取得するために)1つの余分なクエリが必要です。

+0

これは、falseを返すことに関するヒントです。 'chunk()'が私の 'whereReady'節を無視していると言っていますか? – eComEvo

+0

@eComEvoいいえ、無視しません。そして、それはそれが変わるのを見たい人の議論の1つです。スキップ/リミットを無視するということです(それはそれらを使う必要があるからです)。しかし、それはクエリに設定された他のすべての条件を尊重します。それは矛盾している。 – patricus

+0

@eComEvoまた、別のオプションを検討して回答を更新しました。ちょうど私が考えた他の何か、それはまだ別の回避策です。 – patricus