2015-07-17 12 views
7

Sto avendo problemi di memoria perché sembra che Django sta caricando gli oggetti in memoria quando si utilizza delete(). C'è un modo per impedire a Django di farlo?Come impedire a django di caricare oggetti in memoria quando si utilizza `delete()`?

Dalla documentazione Django:

Django deve recuperare oggetti in memoria per inviare segnali e gestire cascate. Tuttavia, se non ci sono cascate e nessun segnale, Django può prendere un percorso veloce ed eliminare oggetti senza recuperare in memoria. Per le eliminazioni di grandi dimensioni ciò può comportare un utilizzo della memoria notevolmente ridotto. Anche la quantità di query eseguite può essere ridotta.

https://docs.djangoproject.com/en/1.8/ref/models/querysets/#delete

Non faccio uso di segnali. Ho delle chiavi esterne sul modello che sto cercando di eliminare, ma non vedo perché Django abbia bisogno di caricare gli oggetti in memoria. Sembra che lo faccia, perché la mia memoria aumenta mentre la query viene eseguita.

+1

Poiché hai chiavi esterne, Django deve caricare gli oggetti per risolvere il modo in cui la relazione deve gestire la cancellazione: https://docs.djangoproject.com/en/1.8/ref/models/fields/#django .db.models.ForeignKey.on_delete – petkostas

+0

@petkostas Ho provato a mettere 'on_delete = models.DO_NOTHING' sui miei campi ForeignKey, ma questo non ha aiutato. Ma non sarebbe comunque una buona soluzione per me, voglio disabilitare il caricamento degli oggetti in memoria per questa specifica query, non voglio che tutte le mie query ignorino i vincoli ForeignKey. – rednaw

+0

Utilizzare sql raw potrebbe essere una soluzione . – NeoWang

risposta

0

È possibile importare la connessione al database Django e usarlo con sql per eliminare. Ho avuto lo stesso problema come te e questo mi aiuta molto. Ecco qualche frammento di (sto usando mysql a proposito, ma è possibile eseguire qualsiasi istruzione SQL):

from django.db import connection 
sql_query = "DELETE FROM usage WHERE date < '%s' ORDER BY date" % date 
cursor = connection.cursor() 
try: 
    cursor.execute(sql_query) 
finally: 
    c.close() 

Questo dovrebbe eseguire solo l'operazione di eliminazione su quel tavolo senza compromettere nessuna delle vostre relazioni modello.

+0

È probabile che la query non riesca a livello di database, poiché gli oggetti eliminati hanno chiavi esterne che puntano a loro, e Django inserisce un vincolo di tipo ON DELETE RESTRICT su chiavi esterne a livello di DB. – baxeico

3

È possibile utilizzare una funzione come questa per iterare su un numero enorme di oggetti senza usare troppa memoria:

import gc 

def queryset_iterator(qs, batchsize = 500, gc_collect = True): 
    iterator = qs.values_list('pk', flat=True).order_by('pk').distinct().iterator() 
    eof = False 
    while not eof: 
     primary_key_buffer = [] 
     try: 
      while len(primary_key_buffer) < batchsize: 
       primary_key_buffer.append(iterator.next()) 
     except StopIteration: 
      eof = True 
     for obj in qs.filter(pk__in=primary_key_buffer).order_by('pk').iterator(): 
      yield obj 
     if gc_collect: 
      gc.collect() 

quindi è possibile utilizzare la funzione per scorrere gli oggetti da eliminare:

for obj in queryset_iterator(HugeQueryset.objects.all()): 
    obj.delete() 

Per ulteriori informazioni è possibile controllare this blog post.

Problemi correlati