我在一个具有5个m2m字段的模型上使用prefetch_related
时遇到了严重的性能问题,并且我还预取了一些嵌套的m2m字段。
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,但总请求时间约为 8 秒。 丝绸时间 我进行了一些分析,发现超过 80% 的时间花在了 prefetch_related_objects 调用上。 分析 我使用 Django==1.8.5 和 djangorestframework==3.4.6。
我愿意采取任何优化方式。感谢您的帮助。
使用select_related
进行编辑:
我尝试了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")
新的结果对于带有32个查询和150ms查询时间的请求仍然是8秒。
编辑:
看起来4年前在Django问题跟踪器上开了一张票,目前仍然未关闭: https://code.djangoproject.com/ticket/20577
prefetch_related
的逻辑而不是SQL查询。 - Lucas Miller