Vor ein paar Tagen stieß ich auf ein unerwartetes Leistungsproblem mit einer ziemlich standardmäßigen Django-Einrichtung. Für ein bevorstehendes Feature müssen wir stündlich eine Tabelle neu generieren, die etwa 100k Zeilen Daten enthält, 9M auf der Festplatte, 10M Indizes laut pgAdmin.
Das Problem ist, dass das Einfügen der Dateien, egal mit welcher Methode, buchstäblich Ewigkeiten dauert, bis zu 3 Minuten bei 100 % Festplattenauslastung. Das ist nichts, was man an einem Produktionsstandort haben möchte. Dabei spielt es keine Rolle, ob die Einfügevorgänge in einer Transaktion, durch einfaches Einfügen, mehrzeiliges Einfügen, COPY FROM oder sogar INSERT INTO t1 SELECT * FROM t2 ausgeführt wurden.
Nachdem ich festgestellt hatte, dass dies nicht die Schuld von Django ist, folgte ich einer Trial-and-Error-Route, und siehe da, das Problem verschwand, nachdem ich alle Fremdschlüssel gelöscht hatte! Statt 3 Minuten dauerte die Ausführung von INSERT INTO SELECT FROM weniger als eine Sekunde, was bei einer Tabelle <= 20M auf der Festplatte nicht allzu überraschend ist. Was ist Seltsam ist, dass PostgreSQL es schafft, Einfügungen um das 180-fache zu verlangsamen, indem es nur 3 Fremdschlüssel verwendet.
Oh, die Festplattenaktivität war reines Schreiben, da alles im RAM zwischengespeichert wird; nur Schreibvorgänge gehen an die Festplatten. Es sieht so aus, als ob PostgreSQL sehr hart arbeitet, um jede Zeile in den verwiesenen Tabellen zu berühren, da 3MB/sec * 180s viel mehr Daten sind als die 20MB, die diese neue Tabelle auf der Platte braucht. Kein WAL für den 180s Fall, ich testete direkt in psql, in Django, füge ~50% Overhead für WAL Logging hinzu. Versucht @commit_on_success, gleiche Langsamkeit, ich hatte sogar multi row insert und COPY FROM mit psycopg2 implementiert. Das ist eine weitere seltsame Sache, wie können 10M Einfügungen im Wert von > 10x 16M Log-Segmente erzeugen?
Tabellenlayout: id serial primary, eine Reihe von int32, 3 Fremdschlüssel zu
- kleine Tabelle, 198 Zeilen, 16k auf Platte
- große Tabelle, 1.2M Zeilen, 59 Daten + 89 Index MB auf Platte
- große Tabelle, 2.2M Zeilen, 198 + 210MB
Also, bin ich dazu verdammt, entweder Drop die Fremdschlüssel manuell oder verwenden Sie die Tabelle in einer sehr un-Django Weise durch die Definition von Speichern bla_id x3 und überspringen Sie mit models.ForeignKey? Ich würde gerne über einige magische Gegenmittel / pg-Einstellung zu hören, dies zu beheben.