Maison  >  Questions et réponses  >  le corps du texte

Optimisez la boucle foreach de Laravel avec 2k et améliorez la récupération relationnelle à partir de 200k pour réduire le temps d'exécution

J'ai un modèle appelé "Produit" J'ai un modèle appelé Note_voucher_line

C'est la relation au sein du produit

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');
}

Maintenant, je dois parfois boucler le produit avec un code comme celui-ci

$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
}

Model Note_voucher_line a plus de 300 000 lignes J'ai un index sur migration Il s'agit de la note_voucher_linesmigration d'index interne

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');
});

La table product a un index appelé product_id Toute aide ici pour le rendre plus rapide Merci

P粉707235568P粉707235568177 Il y a quelques jours371

répondre à tous(2)je répondrai

  • P粉492959599

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

    Dans ce cas, charger votre relation avec impatience peut être utile.

    $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
    }

    Ce qui se passe ici, c'est que nous utilisons la table with() 方法在每次迭代中从 note_voucher_lines pour précharger 2 000 lignes (en supposant que votre table de produits contient 2 000 lignes) au lieu de la ligne chargée auparavant. Cela réduit le nombre d'appels réseau effectués vers le serveur de base de données. Désormais, au lieu de 300 000 appels, il effectue 300 000/2 000 appels.

    Remarque : vous devez également envisager d'utiliser le chargement par blocs pour votre produit afin d'éviter d'atteindre les limites de mémoire à mesure que vos données continuent de croître. https://laravel.com/docs/10.x/eloquent#chunking-results

    répondre
    0
  • P粉244730625

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

    La principale raison du retard semble être le chargement paresseux de la relation get_note_voucher_lines.

    Chaque fois que vous accédez à cette relation dans une boucle, Laravel effectuera une requête distincte pour obtenir les lignes pertinentes. C’est ce qu’on appelle le problème N+1.

    Pour atténuer cela, utilisez le chargement rapide :

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

    Vous pouvez également utiliser le chunking pour traiter le Big Data :

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

    Assurez-vous qu'il y a un index sur le champ id. Vous avez mentionné avoir un index, mais assurez-vous qu'il s'agit d'un index approprié et pas seulement d'une contrainte de clé étrangère.

    répondre
    0
  • Annulerrépondre