簡體   English   中英

優化Django子查詢(當前使用`annotate`和`Count`)

[英]Optimise Django subquery (currently using `annotate` and `Count`)

使用: Django 1.11,Postgres 9.6

我需要優化Django ORM查詢以供Django Rest Framework使用。 查詢必須返回以下記錄:

  1. target字段中匹配ID列表
  2. 將結果集限制為在source ID中多次出現source ID的記錄。

當前的方法是使用annotateCount來創建子查詢,但是添加到分頁中的每個請求背后的處理量非常大,這意味着該應用導致超時或行為非常緩慢。

如果服務器上的Postgres作為原始查詢可以完成任何事情,那么我很好。

模型:

class Relationship(models.Model):
    id = models.AutoField(primary_key=True)
    source = models.BigIntegerField(db_index=True)
    target = models.BigIntegerField(db_index=True)

查看摘要:

match_list = [123, 456, 789] # dummy data for example
queryset = Relationship.objects.filter(target__in=match_list)
sub_queryset = (Relationship.objects.filter(target__in=_match_list)
                                    .values('source')
                                    .annotate(source_count=Count("source"))
                                    .filter(source_count__gt=1)
                                    )
sub_ids = [i["source"] for i in sub_queryset]
queryset = (queryset.filter(source__in=sub_ids)
            )

API將目標ID的列表作為參數,並以連接到該目標的所有source ID的列表作為響應。 但是,我正在過濾查詢集以僅返回連接到兩個或多個targetsource記錄。

作為背景,最終的查詢集將由Django Rest Framework提供服務,並且當前正在導致超時,因為請求的數量呈指數增長的時間越長

注意 :之所以將其放在SO上,是因為它導致我的請求超時並因此導致錯誤。 我知道我可以延長超時時間,但寧願優化查詢。 我考慮過CodeReview,但覺得這更合適。

編輯1 :按照@albar的建議,它當前是一個單獨的子查詢,因為annotate / Count操作僅在返回值而不是完整記錄時有效

一種可能的解決方案是使用相關子查詢:

duplicates = Relationship.objects.exclude(
    id=OuterRef('id')
).filter(source=OuterRef('source'))

Relationship.objects.annotate(
    duplicated=Exists(duplicates)
).filter(
    duplicated=True
)

這樣做是建立一個查詢集(無法單獨評估),該查詢集將僅包含與主查詢集的“源”值重復的元素。 然后,它過濾元素,以便僅選擇那些元素。

在django中沒有.annotate(...).filter(...)情況下,目前.annotate(...).filter(...)無法做到這一點,但是有時會影響性能:僅在數據庫中(在WHERE子句中)對其進行評估就可以對性能進行重大改進。

暫無
暫無

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

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