Beschleunigen Sie Datenbank-Einsätze von ORM
-
05-07-2019 - |
Frage
Ich habe eine Django Ansicht, die 500-5000 neue Datenbank EINSäTZE in einer Schleife erzeugt. Das Problem ist, es ist wirklich langsam! Ich erhalte etwa 100 Einsätze pro Minute auf Postgres 8.3. Wir verwenden MySQL auf weniger Hardware (kleinere EC2-Instanz) zu verwenden, und hatten nie diese Art von Fehlern.
Details: Postgres 8.3 auf Ubuntu Server 9.04. Server ist eine "große" Amazon EC2 mit Datenbank auf EBS (ext3) -. 11GB / 20GB
Hier einige meiner postgresql.conf - lassen Sie mich wissen, wenn Sie mehr benötigen
shared_buffers = 4000MB
effective_cache_size = 7128MB
Mein Python:
for k in kw:
k = k.lower()
p = ProfileKeyword(profile=self)
logging.debug(k)
p.keyword, created = Keyword.objects.get_or_create(keyword=k, defaults={'keyword':k,})
if not created and ProfileKeyword.objects.filter(profile=self, keyword=p.keyword).count():
#checking created is just a small optimization to save some database hits on new keywords
pass #duplicate entry
else:
p.save()
Einige Ausgabe von oben:
top - 16:56:22 up 21 days, 20:55, 4 users, load average: 0.99, 1.01, 0.94
Tasks: 68 total, 1 running, 67 sleeping, 0 stopped, 0 zombie
Cpu(s): 5.8%us, 0.2%sy, 0.0%ni, 90.5%id, 0.7%wa, 0.0%hi, 0.0%si, 2.8%st
Mem: 15736360k total, 12527788k used, 3208572k free, 332188k buffers
Swap: 0k total, 0k used, 0k free, 11322048k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
14767 postgres 25 0 4164m 117m 114m S 22 0.8 2:52.00 postgres
1 root 20 0 4024 700 592 S 0 0.0 0:01.09 init
2 root RT 0 0 0 0 S 0 0.0 0:11.76 migration/0
3 root 34 19 0 0 0 S 0 0.0 0:00.00 ksoftirqd/0
4 root RT 0 0 0 0 S 0 0.0 0:00.00 watchdog/0
5 root 10 -5 0 0 0 S 0 0.0 0:00.08 events/0
6 root 11 -5 0 0 0 S 0 0.0 0:00.00 khelper
7 root 10 -5 0 0 0 S 0 0.0 0:00.00 kthread
9 root 10 -5 0 0 0 S 0 0.0 0:00.00 xenwatch
10 root 10 -5 0 0 0 S 0 0.0 0:00.00 xenbus
18 root RT -5 0 0 0 S 0 0.0 0:11.84 migration/1
19 root 34 19 0 0 0 S 0 0.0 0:00.01 ksoftirqd/1
Lassen Sie mich wissen, ob irgendwelche anderen Details hilfreich wäre.
Lösung
Zum eine ORM-Operationen sein werden immer langsamer als reine SQL. Ich schrieb einmal ein Update zu einer großen Datenbank in ORM-Code und setzen Sie ihn laufen, aber es nach einigen Stunden beendet, wenn es nur einen winzigen Bruchteil abgeschlossen hatte. Nach Umschreiben es in SQL das Ganze lief in weniger als eine Minute.
Zweitens, denken Sie daran, dass Ihr Code hier ist für jede Zeile in Ihrem Datensatz zu vier separaten Datenbankoperationen zu tun up - die get
in get_or_create, möglicherweise auch die create
, die count
auf dem Filter und schließlich die save
. Das ist eine Menge von Datenbankzugriff.
Bedenkt man, dass ein Maximum von 5000 Objekten nicht sehr groß ist, sollten Sie zu Beginn des gesamten Datensatz in dem Speicher lesen können. Dann können Sie eine einzelne filter
tun alle vorhandenen Keyword-Objekte auf einmal zu bekommen, eine große Anzahl von Abfragen in der Keyword get_or_create
speichern und auch die Notwendigkeit, die Vermeidung doppelter ProfileKeywords in erster Linie zu instanziiert.
Andere Tipps
Ein häufiger Grund für die langsamen Massenoperationen wie diese ist jeder Einsatz in einer eigenen Transaktion geschieht. Wenn Sie alle von ihnen bekommen können in einer einzigen Transaktion passieren, könnte es viel schneller gehen.