darryldecode / laravelshoppingcart

Shopping Cart Implementation for Laravel Framework
1.35k stars 452 forks source link

Slow performance when using database and associatedModel #221

Open vlados opened 4 years ago

vlados commented 4 years ago

I've implemented the database as a storage but I see very bad performance. Example: I add a multiple items to the cart. Every cart item is a product which have multiple relations like media. When I add 25 different items to the cart it's executing 355 selects, where if I have 1 item - 29 queries So my question is how to optimize this?

Model Query Time
DatabaseStorageModel SELECT * FROM "cart_storage" WHERE "cart_storage"."id" = '3_cart_items' LIMIT 1DatabaseStorage.php:11 5.51 ms
DatabaseStorageModel SELECT * FROM "cart_storage" WHERE "cart_storage"."id" = '3_cart_items' LIMIT 1DatabaseStorage.php:17 8.04 ms
DatabaseStorageModel SELECT * FROM "cart_storage" WHERE "cart_storage"."id" = '3_cart_conditions' LIMIT 1DatabaseStorage.php:11 4.87 ms
DatabaseStorageModel SELECT * FROM "cart_storage" WHERE "cart_storage"."id" = '3_cart_items' LIMIT 1DatabaseStorage.php:11 12.04 ms
DatabaseStorageModel SELECT * FROM "cart_storage" WHERE "cart_storage"."id" = '3_cart_items' LIMIT 1DatabaseStorage.php:17 7.85 ms
DatabaseStorageModel SELECT * FROM "cart_storage" WHERE "cart_storage"."id" = '3_cart_conditions' LIMIT 1DatabaseStorage.php:11 7.38 ms
DatabaseStorageModel SELECT * FROM "cart_storage" WHERE "cart_storage"."id" = '3_cart_conditions' LIMIT 1DatabaseStorage.php:11 7.46 ms
DatabaseStorageModel SELECT * FROM "cart_storage" WHERE "cart_storage"."id" = '3_cart_items' LIMIT 1DatabaseStorage.php:11 4.46 ms
DatabaseStorageModel SELECT * FROM "cart_storage" WHERE "cart_storage"."id" = '3_cart_items' LIMIT 1DatabaseStorage.php:17 5.27 ms
DatabaseStorageModel SELECT * FROM "cart_storage" WHERE "cart_storage"."id" = '3_cart_conditions' LIMIT 1DatabaseStorage.php:11 7.67 ms
DatabaseStorageModel SELECT * FROM "cart_storage" WHERE "cart_storage"."id" = '3_cart_conditions' LIMIT 1DatabaseStorage.php:11 8.85 ms
DatabaseStorageModel SELECT * FROM "cart_storage" WHERE "cart_storage"."id" = '3_cart_items' LIMIT 1DatabaseStorage.php:11 5.48 ms
DatabaseStorageModel SELECT * FROM "cart_storage" WHERE "cart_storage"."id" = '3_cart_items' LIMIT 1
vanthao03596 commented 4 years ago

Same issue. How we can eager loading associatedModel ?

vlados commented 4 years ago

I suggest to load all items with one query and add a param associatedModelWith()

        $product = Product::with(['media','category'])->findOrFail(\request('product_id'));
        $cart->add(array(
            'id' => $product->id,
            'name' => $product->name,
            'price' => $product->price_numeric,
            'quantity' => 1,
            'attributes' => array(),
            'associatedModel' => $product,
            'associatedModelWith' => ['media','category']
        ));
darryldecode commented 4 years ago

I suggest you preload any needed related data in custom property of the model object before associating it. So the associated model will be lean as possible and does not need to perform any queries to display its media files and category names during cart loops. And we let the cart package handle its sole purpose.

Example, if you need Image Source and Category Name, add it as plain data in a custom property of the object model before associating it. Make sure that media image url and category name text is already in object's property so there is no need to call relationships on the fly. It's like we flatten data before associating it.

We all know laravel eloquent relationship is slow when we aren't careful, example, if you have Product with eloquent relationship media and category, then you perform a loop and call relationship data on the fly, it will perform queries on each loop which will surely generate worst performance. Example if you do:

$products = $products::all();
$products->each(function($product) {
    echo $product->media->link;
    echo $product->category->name;
})

This will perform a query for everyloop which is very bad. Please enlighten me if I am missing something! Happy coding :)