[英]Optimise Django subquery (currently using `annotate` and `Count`)
使用: Django 1.11,Postgres 9.6
我需要優化Django ORM查詢以供Django Rest Framework使用。 查詢必須返回以下記錄:
target
字段中匹配ID列表 source
ID中多次出現source
ID的記錄。 當前的方法是使用annotate
和Count
來創建子查詢,但是添加到分頁中的每個請求背后的處理量非常大,這意味着該應用導致超時或行為非常緩慢。
如果服務器上的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的列表作為響應。 但是,我正在過濾查詢集以僅返回連接到兩個或多個target
的source
記錄。
作為背景,最終的查詢集將由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.