Je rencontre de sérieux problèmes de performances avec prefetch_related
sur un modèle avec 5 m2m de champs et je préextrait aussi quelques champs m2m imbriqués.Django prefetch_related optimise la requête mais reste très lent
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()
Le nombre de requête est très bien et le temps de requête de base de données est bien aussi, pour exemple si j'interroger 700 objets de mon modèle j'ai 35 requête et le temps de recherche moyen est de 100 ~ 200 ms, mais le temps de la demande totale est d'environ 8 secondes.
J'ai couru un certain profilage et il a fait remarquer que plus de 80% du temps passé était l'appel prefetch_related_objects
.
J'utilise Django==1.8.5
et djangorestframework==3.4.6
Je suis ouvert à toute façon d'optimiser cela. Merci d'avance pour votre aide.
Modifier avec select_related
:
J'ai essayé l'amélioration proposée par 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")
Le nouveau résultat est encore 8 secondes pour la demande avec 32 requêtes et 150ms de requête temps.
Edit:
Il semble qu'un ticket a été ouvert sur le suivi des problèmes Django il y a 4 ans et est encore ouvert: https: //code.djangoproject.com/ticket/20577
Ok, j'ai essayé et le résultat n'est pas vraiment meilleur.J'ai 4 requêtes de moins mais le temps global est toujours de 8 secondes. Je pense que le problème est plus dans la logique de 'prefetch_related' au lieu des requêtes sql. –