Repository: saleor/saleor

Issue:
Placing an order with one product line results in lots of database queries
### What I'm trying to achieve
I'm running a stress test and while the store is quite responsive, I feel that 111 database queries are probably more than needed.

### Steps to reproduce the problem
1. Run the `checkoutComplete` mutation

```
mutation completeCheckout($checkoutId: ID!) {
  checkoutComplete(checkoutId: $checkoutId) {
    errors {
      field
      message
      __typename
    }
    order {
      id
      token
      __typename
    }
    __typename
  }
}
```

### What I expected to happen
I expected there to be fewer database queries 😄 

### Screenshots
![image](https://user-images.githubusercontent.com/81205/58488787-4b382d00-816a-11e9-9df0-ef894665a454.png)

Please note that some of these actually need to be executed twice because my test setup runs Celery in eager mode. Fetching product collections 16 times is probably not necessary though.


Discussion:
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.


Resolving patch:
diff --git a/saleor/graphql/checkout/mutations.py b/saleor/graphql/checkout/mutations.py
--- a/saleor/graphql/checkout/mutations.py
+++ b/saleor/graphql/checkout/mutations.py
@@ -4,6 +4,7 @@
 from django.conf import settings
 from django.core.exceptions import ObjectDoesNotExist, ValidationError
 from django.db import transaction
+from django.db.models import Prefetch
 from django.utils import timezone
 
 from ...checkout import models
@@ -29,7 +30,7 @@
 from ...core.exceptions import InsufficientStock
 from ...core.taxes import TaxError
 from ...discount import models as voucher_model
-from ...payment import PaymentError, gateway
+from ...payment import PaymentError, gateway, models as payment_models
 from ...payment.interface import AddressData
 from ...payment.utils import store_customer_id
 from ...product import models as product_models
@@ -644,11 +645,25 @@ class Meta:
     @classmethod
     def perform_mutation(cls, _root, info, checkout_id, store_source):
         checkout = cls.get_node_or_error(
-            info, checkout_id, only_type=Checkout, field="checkout_id"
+            info,
+            checkout_id,
+            only_type=Checkout,
+            field="checkout_id",
+            qs=models.Checkout.objects.prefetch_related(
+                "gift_cards",
+                "lines",
+                Prefetch(
+                    "payments",
+                    queryset=payment_models.Payment.objects.prefetch_related(
+                        "order", "order__lines"
+                    ),
+                ),
+            ).select_related("shipping_method", "shipping_method__shipping_zone"),
         )
 
+        discounts = info.context.discounts
         user = info.context.user
-        clean_checkout(checkout, info.context.discounts)
+        clean_checkout(checkout, discounts)
 
         payment = checkout.get_last_active_payment()
 
@@ -657,7 +672,7 @@ def perform_mutation(cls, _root, info, checkout_id, store_source):
                 order_data = prepare_order_data(
                     checkout=checkout,
                     tracking_code=analytics.get_client_id(info.context),
-                    discounts=info.context.discounts,
+                    discounts=discounts,
                 )
             except InsufficientStock as e:
                 raise ValidationError(


Test patch: