2
votes

Une requête simple provoque une fuite de mémoire dans Django

Je travaille dans une entreprise qui possède une grande base de données et je souhaite effectuer quelques requêtes de mise à jour dessus mais cela semble provoquer une énorme fuite de mémoire la requête est la suivante

with transaction.atomic()

J'ai écrit ceci dans le shell interactif de Django

J'ai même essayé d'utiliser

c= CallLog.objects.all()
for i in c:
   i.cdate = pytz.utc.localize(datetime.datetime.strptime(i.fixed_date, "%y-%m-%d %H:%M"))
   i.save()

mais cela n'a pas fonctionné, avez-vous une idée de comment puis-je détecter la source de

l'ensemble de données sur lequel je travaille est d'environ 27 millions

fixed_date est une propriété calculée


3 commentaires

Pourquoi dites-vous que c'est une fuite de mémoire? Que se passe-t-il lorsque vous exécutez ce code? Une trace de pile d'erreur que vous pourriez ajouter?


J'ai une machine mémoire de 4 Go et quand je lance htop, je vois que toute la mémoire a été mangée par Django et le système se fige après cela


Vous devez utiliser Redis ou une sorte de gestionnaire de file d'attente pour traiter toutes les données 1 par 1


3 Réponses :


1
votes

Vous pouvez essayer quelque chose comme ceci:

from django.core.paginator import Paginator

p = Paginator(CallLog.objects.all().only('cdate'), 2000)
for page in range(1, p.num_pages + 1):
    for i in p.page(page).object_list:
        i.cdate = pytz.utc.localize(datetime.datetime.strptime(i.fixed_date, "%y-%m-%d %H:%M"))
        i.save()

Le découpage d'un ensemble de requêtes ne charge pas tous les objets en mémoire uniquement pour obtenir un sous-ensemble mais ajoute une limite et un décalage à la requête SQL avant de frapper le base de données.


4 commentaires

Je pense que ce morceau de code met à jour toute la table avec la même valeur, et je veux mettre à jour chaque enregistrement avec sa valeur de fixed_date calculée. J'ai pensé à l'expression F () mais cela ne fonctionne pas avec les propriétés calculées


@AhmedIbrahim J'ai édité ma réponse. Essayez ceci, cela devrait fonctionner un peu mieux. Si cela prend du temps et consomme de la mémoire, vous devez penser à créer une tâche asynchrone et informer l'utilisateur quand c'est terminé.


J'essaierai celui-ci et je vous répondrai


cela fonctionne parfaitement mais si lentement, mais cela n'a pas d'importance car je ne le fais qu'une fois




0
votes

Essayez de le diviser en petits blocs (puisque vous n'avez que 4 Go de RAM)

c= CallLog.objects.filter(somefield=somevalue)

Lorsque c'est nécessaire, j'utilise généralement un caractère ou un nombre (ID entrant en 1,2,3, 4 etc)


0 commentaires