簡體   English   中英

子查詢的使用非常慢

[英]Usage of Subquery very slow

我有以下查詢,但需要大約 1:20 分鍾才能完成:

user_total_revenue = (
    User.objects.annotate(
        total_revenue=Sum("payments__amount"),
        first_order_date=Subquery(
            User.objects.filter(pk=OuterRef("pk"))
            .annotate(first_order_date=Min("shops__orders__created"))
            .values("first_order_date"),
            output_field=DateTimeField(),
        ),
    )
)

原始 SQL 查詢:

SELECT
   "users_user"."id",
   "users_user"."created",
   "users_user"."updated",
   "users_user"."user_id",
   "users_user"."name",
   "users_user"."address",
   SUM("payments_payment"."amount") AS "total_revenue",
   (
      SELECT
         MIN(U2."created") AS "first_order_date" 
      FROM
         "users_user" U0 
         LEFT OUTER JOIN
            "shops_shop" U1 
            ON (U0."id" = U1."user_id") 
         LEFT OUTER JOIN
            "orders_order" U2 
            ON (U1."id" = U2."shop_id") 
      WHERE
         U0."id" = 
         (
            "users_user"."id"
         )
      GROUP BY
         U0."id"
   )
   AS "first_order_date" 
FROM
   "users_user" 
   LEFT OUTER JOIN
      "payments_payment" 
      ON ("users_user"."id" = "payments_payment"."user_id") 
GROUP BY
   "users_user"."id",
   (
      SELECT
         MIN(U2."created") AS "first_order_date" 
      FROM
         "users_user" U0 
         LEFT OUTER JOIN
            "shops_shop" U1 
            ON (U0."id" = U1."user_id") 
         LEFT OUTER JOIN
            "orders_order" U2 
            ON (U1."id" = U2."shop_id") 
      WHERE
         U0."id" = 
         (
            "users_user"."id"
         )
      GROUP BY
         U0."id"
   )
   LIMIT 21

因為它太慢了,所以我用不同的方式寫了它,速度要快得多(< 1 秒):

def user_total_revenue():
    first_orders = (
        User.objects.annotate(first_order_date=Min("shops__orders__created"))
        .values("pk", "first_order_date")
    )
    first_orders = {
        item["pk"]: item["first_order_date"] for item in first_orders
    }

    user_total_revenue = User.objects.annotate(total_revenue=Sum("payments__amount"))

    return [
        {
            "user": user,
            "first_order_date": first_orders[user.pk],
        }
        for user in user_total_revenue
    ]

我想了解為什么我的第一個版本使用子查詢如此緩慢。

這里不是 100%,但我相信由此產生的查詢應該更快。

from django.db.models.functions import Coalesce
from django.db.models import Value

user_total_revenue = User.objects.annotate(
    total_revenue=Coalesce(
        Subquery(
            Payment.object.filter(user_id=OuterRef("pk"))
            .values("user_id")
            .annotate(sum=Sum("amount"))
            .values("sum")[:1]
        ),
        Value(0),
    ),
    first_order_date=Subquery(
        User.objects.filter(pk=OuterRef("pk"))
        .annotate(first_order_date=Min("shops__orders__created"))
        .values("first_order_date"),
        output_field=DateTimeField(),
    ),
)

其他嘗試:

  • 使用order_by("shops__orders__created")並選擇第一個項目而不是Min

  • 添加索引以created訂單

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM