2017-03-16 56 views
0

我遇到一些嚴重的性能問題與prefetch_related Model 5 m2m領域,我預取也很少嵌套m2m領域。Django prefetch_related優化查詢,但仍然非常緩慢

class TaskModelManager(models.Manager): 
    def get_queryset(self): 
     return super(TaskModelManager, self).get_queryset().exclude(internalStatus=2).prefetch_related("parent", "takes", "takes__flags", "assignedUser", "assignedUser__flags", "asset", "asset__flags", "status", "approvalWorkflow", "viewers", "requires", "linkedTasks", "activities") 


class Task(models.Model): 
    uuid = models.UUIDField(primary_key=True, default=genOptimUUID, editable=False) 
    internalStatus = models.IntegerField(default=0) 
    parent = models.ForeignKey("self", blank=True, null=True, related_name="childs") 
    name = models.CharField(max_length=45) 
    taskType = models.ForeignKey("TaskType", null=True) 
    priority = models.IntegerField() 
    startDate = models.DateTimeField() 
    endDate = models.DateTimeField() 
    status = models.ForeignKey("ProgressionStatus") 
    assignedUser = models.ForeignKey("Asset", related_name="tasksAssigned") 
    asset = models.ForeignKey("Asset", related_name="tasksSubject") 
    viewers = models.ManyToManyField("Asset", blank=True, related_name="followedTasks") 
    step = models.ForeignKey("Step", blank=True, null=True, related_name="tasks") 
    approvalWorkflow = models.ForeignKey("ApprovalWorkflow") 
    linkedTasks = models.ManyToManyField("self", symmetrical=False, blank=True, related_name="linkedTo") 
    requires = models.ManyToManyField("self", symmetrical=False, blank=True, related_name="depends") 

    objects = TaskModelManager() 

查詢的數量是好的,數據庫查詢時間也沒關係,對於爲例,如果我詢問我的模型700點的對象,我有35查詢,平均查詢時間爲100〜200毫秒,但總的請求時間大約是8秒。

silk times

我碰到一些剖析,並指出,時間超過80%是花費在prefetch_related_objects通話。

profiling

我使用Django==1.8.5djangorestframework==3.4.6

我歡迎任何方式來優化這個。 在此先感謝您的幫助。


編輯與select_related

我試圖通過麥金太爾

class TaskModelManager(models.Manager): 
    def get_queryset(self): 
     return super(TaskModelManager, self).get_queryset().exclude(internalStatus=2).select_related("parent", "status", "approvalWorkflow", "step").prefetch_related("takes", "takes__flags", "assignedUser", "assignedUser__flags", "asset", "asset__flags", "viewers", "requires", "linkedTasks", "activities") 

新的結果仍是8秒與32個查詢和查詢的150ms的要求提出了改進時間。


編輯:

看來,門票已於Django的問題跟蹤3年前開業,是仍處於打開狀態:HTTPS://code.djangoproject.com/ticket/20577

回答

1

嘗試使用select_related作爲外鍵,如parentApprovalWorkflow而不是prefetch_related

當您使用select_related時,Django將使用連接來獲取模型,而prefetch_related會導致額外的查詢。您可能會發現這可以提高性能。

+0

好的,我試過了,結果不是很好。我有4個較少的查詢,但總體時間仍然是8秒。我認爲這個問題更多的是在'prefetch_related'而不是sql查詢的邏輯中。 –

0

如果數據庫爲150毫秒,但您的請求爲8秒,則不是您的查詢(本身至少)。一些可能的問題:

1)您的HTML或模板太複雜,花費太多時間來生成響應。或者考慮template caching.

2)所有這些對象都很複雜,而且你加載了太多的字段,所以在查詢速度很快的時候,發送它並在Python中處理所有這些對象是很慢的。只使用(),延遲()和values()或value_list()來加載你需要的東西。

優化很難,我們需要更多的細節給你一個更好的主意。我建議安裝Django調試工具欄(Django應用程序)或Opbeat(第三方實用程序),它們可以幫助您檢測您的時間花費在哪裏,然後您可以相應地進行優化。