suchen

Heim  >  Fragen und Antworten  >  Hauptteil

Optimieren Sie die foreach-Schleife von Laravel mit 2 KB und verbessern Sie den relationalen Abruf von 200 KB, um die Ausführungszeit zu verkürzen

Ich habe ein Modell namens „Produkt“ Ich habe ein Modell namens Note_voucher_line

Das ist die Beziehung innerhalb des Produkts

public function get_note_voucher_lines()
{
    return $this->hasMany('App\Models\Note_voucher_line','product_id','id')->orderBy('date','asc')->orderBy('note_voucher_id','asc');
}

Jetzt muss ich manchmal das Produkt mit Code wie diesem schleifen

$products = Product::whereBetween('id',[$num1,$num2])->get();
foreach($products as $product)
{
    $lines = $product['get_note_voucher_lines'];
    // when i use this relation it tack long long time
}

Modell Note_voucher_line hat über 300.000 Zeilen Ich habe einen Index für migration Dies ist eine note_voucher_linesinterne Indexmigration

Schema::table('note_voucher_lines', function($table) {
    $table->foreign('note_voucher_id')->references('id')->on('note_vouchers');
    $table->foreign('user_id')->references('id')->on('users');
    $table->foreign('journal_entry_id')->references('id')->on('journal_entries');
    $table->foreign('warehouse_id')->references('id')->on('warehouses');
    $table->foreign('product_id')->references('id')->on('products');
    $table->foreign('cost_center_id')->references('id')->on('cost_centers');
    $table->foreign('unit_id')->references('id')->on('units');
    $table->foreign('is_it_bonus')->references('id')->on('status');
    $table->foreign('note_voucher_type_id')->references('id')->on('note_voucher_types');
    $table->foreign('posting_state_id')->references('id')->on('posting_status');
    $table->foreign('product_total_quantity_id')->references('id')->on('product_total_quantitys');
    $table->foreign('is_componentable')->references('id')->on('status');
    $table->foreign('approved_state_id')->references('id')->on('approval_status');
    $table->foreign('currency_id')->references('id')->on('currencies');
    $table->foreign('branch_id')->references('id')->on('branches');
    $table->foreign('created_by')->references('id')->on('users');
    $table->foreign('deleted_by')->references('id')->on('users');
});

Die Produkttabelle hat einen Index namens product_id Irgendeine Hilfe hier, um es schneller zu machen Danke

P粉707235568P粉707235568245 Tage vor458

Antworte allen(2)Ich werde antworten

  • P粉492959599

    P粉4929595992024-03-31 12:05:45

    在这种情况下,急切地加载你们的关系会很有帮助。

    $products = Product::whereBetween('id',[$num1,$num2])->with('get_note_voucher_lines')->get();
    foreach($products as $product)
    {
        $lines = $product->get_note_voucher_lines;
        // This should be faster and note that this is the right way to fetch laravel relation not as an array
    }

    这里发生的情况是,我们使用 with() 方法在每次迭代中从 note_voucher_lines 表预加载 2k 行(假设您的产品表包含 2k 行),而不是之前加载的一行。这减少了对数据库服务器进行的网络调用次数,现在不再进行 300k 次调用,而是进行 300k/2k 次调用。

    注意:您还应该考虑对您的产品使用块加载,以避免随着数据的持续增长而达到内存限制。 https://laravel.com/docs/10.x/eloquent#chunking-结果

    Antwort
    0
  • P粉244730625

    P粉2447306252024-03-31 09:24:23

    延迟的主要原因似乎是 get_note_voucher_lines 关系的延迟加载。

    每次您在循环内访问此关系时,Laravel 都会进行单独的查询来获取相关行。这就是所谓的 N+1 问题。

    为了缓解这种情况,请使用预先加载:

    $products = Product::whereBetween('id',[$num1,$num2])->with('get_note_voucher_lines')->get();

    您还可以使用分块来处理大数据:

    Product::whereBetween('id',[$num1,$num2])->with('get_note_voucher_lines')->chunk(100, function ($products) {
    foreach ($products as $product) {
    
         $lines = $product->get_note_voucher_lines;
    }});

    确保 id 字段上有索引。您提到有一个索引,但请确保它是一个正确的索引,而不仅仅是外键约束。

    Antwort
    0
  • StornierenAntwort