Begrenzung der Verwendung des Speichers in eine *Große* Django QuerySet
Ich habe eine Aufgabe, die ausgeführt werden muss, auf "die meisten" Objekte in meiner Datenbank einmal alle einige Zeit (einmal am Tag, einmal in der Woche, was auch immer). Im Grunde bedeutet dies, dass ich habe einige Abfragen, die wie folgt aussieht läuft in einem eigenen thread.
for model_instance in SomeModel.objects.all():
do_something(model_instance)
(Beachten Sie, dass es tatsächlich ein filter() nicht alle (), aber none-the-less ich noch bis Ende der Auswahl eines sehr große set der Objekte).
Das problem das ich laufen in ist, dass nach der Ausführung für eine Weile den thread getötet von meinem hosting-provider, denn ich bin mit zu viel Speicher. Ich bin vorausgesetzt alle diese Speicher verwenden, geschieht, weil, obwohl die QuerySet
Objekt zurückgegeben durch meine Abfrage hat zunächst einen sehr kleinen Speicher-footprint landet es wächst, wie die QuerySet
Objekt-caches jeder model_instance
wie ich Durchlaufen, Sie.
Meine Frage ist, "was ist der beste Weg zu Durchlaufen fast jede SomeModel
in meiner Datenbank in einem Speicher effizient zu gestalten?" oder vielleicht ist meine Frage "wie kann ich " un-cache' Modell-Instanzen aus einem django queryset?"
EDIT: ich bin eigentlich mit dem Ergebnis der queryset zu bauen, eine Reihe von neuen Objekten. Als solcher habe ich nicht am Ende der Aktualisierung der abgefragt-für die Objekte überhaupt.
- Du wirst einige Hinweise auf das, was du tust mit den queryset. Django hat Regeln, und eine Anzahl von Operationen erfordern das laden des gesamten QuerySet in den Speicher, wo andere Operationen lediglich Prozess die Zeilen ein-at-a-time. docs.djangoproject.com/en/1.2/topics/db/queries/.... Bitte geben Sie einige Hinweise auf, wie du mit Ihr QuerySet-Objekte.
- Sorry, ich sollte angeben, dass ich die Informationen aus den QuerySet-Objekte um neue Objekte zu erstellen (eines anderen Typs). Also ich bin eigentlich nie aktualisieren der Objekte bin ich mit dem Abfragen.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Also, was ich eigentlich am Ende machen, ist, etwas zu bauen, dass Sie 'wrap' ein QuerySet in. Es funktioniert, indem Sie ein deepcopy des QuerySet, mit dem slice-syntax--z.B.
some_queryset[15:45]
- aber dann macht es ein anderer deepcopy des ursprünglichen QuerySet, wenn die Scheibe vollständig Durchlaufen. Dies bedeutet, dass nur die Gruppe von Objekten zurückgegeben, die in 'diesem' bestimmtes Segment im Speicher gespeichert werden.Also statt...
Würden Sie tun...
Bitte beachten Sie, dass die Absicht, dies zu speichern Speicher in Ihrem Python-interpreter. Es wird im wesentlichen durch mehr - Datenbank Abfragen. In der Regel Menschen versuchen, tun das genaue Gegenteil, D. H., minimieren Datenbank-Abfragen so weit wie möglich ohne Bezug auf die Speichernutzung. Hoffentlich jemand finden diese nützlich, obwohl.
Was ist mit django core Paginator-und Seiten-Objekte, die hier dokumentiert:
https://docs.djangoproject.com/en/dev/topics/pagination/
Etwas wie dieses:
iterator()
? docs.djangoproject.com/en/2.1/ref/models/querysets/#iterator In der Tat, Paginator rufencount
ersten (len sonst). Nicht Sie machen etwas mehr ineffizient? Warum sollte diese option besser sein, als mit iterator?for page_idx in range(1, paginator.num_pages+1):
oder Sie überspringen der letzten SeiteKönnen Sie nicht einfach nutzen-Modell.Objekte.alle().iterator() verwenden, da es zu Holen alle die Elemente, die Sie Tabelle auf einmal. Sie können auch nicht einfach gehen mit dem Modell.Objekte.alle()[offset:offset+pagesize] Weg, denn es wird fangen Sie Ihre Ergebnisse. Alle diese übertreffen Ihre memory limit.
Ich habe versucht, mischen sich beide Lösungen und es funktionierte:
Ändern pagesize passt sich Ihren Anforderungen an, und Optional ändern Sie die [offset : offset + pagesize], um die [offset * pagesize : (offset + 1) * pagesize] idiom, wenn es Ihnen besser passt. Auch, natürlich, ersetzen Sie das Modell von Ihrem tatsächlichen Modell-name.
Viele Lösungen implementieren Sie die sql
OFFSET
undLIMIT
über schneiden den queryset. Als stefano Noten, mit größerer Datensätze, wird dies sehr ineffizient. Die richtige Art des Umgangs mit diesen ist die Verwendung von server-side-cursers zu verfolgen, die dem OFFSET.Native server-side cursor-Unterstützung ist in den arbeiten für django. Bis es fertig ist, hier ist eine einfache Umsetzung wenn Sie mit postgres mit dem psycopg2 backend:
Sehen in diesem blog-post für eine tolle Erklärung von Problemen mit dem Arbeitsspeicher von großen Anfragen in django.
sql, params = queryset.query.get_compiler(using=queryset.db).as_sql()
um die SQL-Abfrage von einem queryset. Und Sie sollten die Verwendung von Tabellen.from_db, um Sie in einem tatsächlichen Fall, auf den letzten Django-Versionen..as_sql()
SELECT
- Anweisung, um die Tabelle erstellen Beispiel am Ende. Gibt es eine Möglichkeit, das zu tun, ohne Analyse der.as_sql()
manuell?Ich bin die Fortsetzung der Forschung und es sieht irgendwie aus wie ich will, zu tun, das entspricht einer SQL-OFFSET und LIMIT, die nach Django Doc ' s auf die Begrenzung Querysets bedeutet, ich will mit dem slice-syntax, z.B.
SomeModel.objects.all()[15:25]
So, ich denke jetzt ist vielleicht so etwas wie dies ist, was ich Suche:
Durch meine Abrechnung dieser würde es so machen, dass
smaller_queryset
würde nie zu groß.Gibt es eine django-snippet für diese:
http://djangosnippets.org/snippets/1949/
Es durchläuft ein queryset durch nachgeben Reihen von kleineren "Brocken" von der original-queryset. Es endet mit deutlich weniger Speicher, während so dass Sie die Feineinstellung für die Geschwindigkeit. Ich benutze es in einem meiner Projekte.