2017-03-16 23 views
0

モデルは5 m2mのモデルのprefetch_relatedで重大なパフォーマンス問題が発生しており、ネストした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〜200msであるが、総要求時間を持ってexempleため、細かすぎます約8秒です。

silk times

私はいくつかのプロファイリングを実行したのだが、費やした時間の80%以上がprefetch_related_objectsコールにあったことを指摘しました。

profiling

私はこれを最適化するために、どのような方法に開いているDjango==1.8.5djangorestframework==3.4.6

を使用しています。 ご協力いただきありがとうございます。


select_relatedと編集:

私は新しい結果はまだクエリの32個のクエリと150msので要求のために8秒であるAlasdair

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") 

によって提案された改善を試してみました時間。


編集:

チケットは4年前Djangoの課題追跡で開かれたようだし、まだ開いてます。https://code.djangoproject.com/ticket/20577

答えて

1

prefetch_relatedの代わりにparentApprovalWorkflowのような外部キーにselect_relatedを使用してみてください。

select_relatedを使用すると、余分なクエリを引き起こすprefetch_relatedのように、Djangoは結合を使用してモデルをフェッチします。これにより、パフォーマンスが向上することがあります。

+0

私は試しましたが、その結果はあまり良くありません。私は4つ少ないクエリを持っているが、全体の時間はまだ8秒です。私は問題がSQLクエリの代わりに 'prefetch_related'のロジックの内側にあると思う。 –

0

DBが150msだがリクエストが8秒の場合、それはあなたのクエリではありません(少なくともそれ以上です)。いくつかの問題が考えられます。

1)HTMLまたはテンプレートが複雑すぎるため、応答を生成するのに時間がかかりすぎます。または考えてくださいtemplate caching.

2)これらのオブジェクトはすべて複雑ですし、あまりにも多くのフィールドを読み込むので、クエリが高速で、送信して、Pythonでこれらのオブジェクトをすべて処理するのが遅いです。 only()、defer()、values()、またはvalue_list()を使って必要なものだけを読み込みます。

最適化は難しく、より良いアイデアを提供するために詳細が必要です。 Django Debug Toolbar(Django app)やOpbeat(3rd party utility)をインストールすることをお勧めします。あなたの時間がどこで使われているかを検出し、それに応じて最適化することができます。

関連する問題