SQLAlchemy optimieren

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Hi,

Vielleicht kennen einige von euch das Problem: ihr habt zwei Rechner, chattet mal von dem einen, mal von dem anderen und die History ist danach furchbar verteilt und man weiß manchmal nicht worauf sich Leute beziehen, wenn sie einen am nächsten Tag anschreiben. Naja, jedenfalls passiert mir das und da ich auf allen (relevanten) Rechner Gajim nutze, dachte ich mir dass ich das doch mergen kann, die History ist ja als SQLIte-Datenbank abgespeichert.

Dazu dachte ich mir, hey, SQLite3 reicht, ergo Python 3. Praktischerweise gibt es SQLAlchemy für Python 3, sogar direkt im Paketmanager, warum nicht. Habe mit SQLAlchemy nie was gemacht, dann ist das ja mal 'ne Gelegenheit.

Gesagt, getan, das Ergebnis ist gajim-logmerge.py.

Nur: es ist enttäuschend langsam. Mein erster Import von 20.000 Einträgen in eine Datenbank mit 160.000 Einträgen hat etwa ne Stunde gedauert, wenn nun inkrementelle Imports dann auch so um die 160.000 Einträge haben dann ist das nahezu unbrauchbar, weil ich keine Lust habe den halben Tag lang meine Logs zu mergen.

Nun habe ich sicherlich nicht optimal Programmier, aber bevor ich mich ans optimieren setze frage ich lieber die erfahreneren Leute hier: was kann mir SQLAlchemy in dieser Situation helfen? Gibt es irgendwelche eingebauten Caching-Strategien? Ich sehe etwa, dass ich die JID "eigentlich" viel zu Ort auf Existenz prüfe, aber bevor ich mir die Arbeit mache das selbst zu cachen: vielleicht kann SQLAlchemy das bereits? Auch ist die Prüfung mit ``all()`` vermutlich nicht so optimal, aber ich war bischen verwundert, dass die Queries kein ``exists()`` haben.

Und wie ich das Prüfen der Nachricht effizienter hinbekomme als das durchsehen aller bestehenden Datensätze ist mir leider auch nicht ganz klar. Ich möchte da jetzt auch nicht am Datenbankschema rumeditieren...

Würde mich über Tipps, Hints und Patches freuen. Ist jetzt sicherlich bisher nicht der beste Code, dazu fehlt mir momentan einfach noch zu viel SQLAlchemy-Verständnis.

grüße,
Leonidas
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Habe noch etwas rumprobiert indem ich die JID-Abfrage gecached habe und die duplizierten Nachrichten mit einer COUNT-Abfrage bestimmen, aber sonderlich schneller wurde das generell nicht. Werd wohl mal schauen, wie man das SQL gedumpt bekommt und es gegen meine DB laufen lassen und gucken ob das einfach so furchtbar ineffizient ist oder ich was anderes falsch mache.

Aktueller Stand.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
deets

Zum dumpen sollte folgendes reichen:

Code: Alles auswählen


  metadata.bind.echo=True.

Uu vorher logging configurieren, fuer den logger

Code: Alles auswählen

  qualname = sqlalchemy.engine

Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ja, das Problem ist, dass ich die Queries zwar rausbekomme, aber nicht mit den Daten. Hab das aber mal mit einigen selbstgebastelten Beispielqueries gemacht und festgestellt, dass die Queries einfach verdammt langsam in SQLite sind, der Overhead von SQLAlchemy war kaum ein Problem.

Habe dann erstmal alle Nachrichten in ein Set eingelesen um darauf effiziente ``in``-Operationen zu haben und ja, das geht dann deutlich schneller. Das heißt also, dass zumindest der inkrementelle Import ab jetzt schnell geht.

Spaßeshalber habe ich mal die Quell- und Ziel-Datenbanken in ein kleines ``tmpfs`` verschoben, bei 20 MB Daten ist sowas ja quasi geschenkt und siehe da von ca. 1h (ich mag das jetzt nicht prüfen, dauert mir zu lange) geht die Zeit runter auf 41 Sekunden :shock: . Inkrementeller Import dauert 5 Sekunden, nachdem er quasi alle Nachrichten skippt.

Ich glaube mir den Zeiten kann ich leben. Wünschte mir aber, dass man SQLite irgendwie sagen kann dass es einfach mal alles in den Speicher packt und erst bei bedarf zurückschreibt. Das ``tmpfs`` macht nen Unterschied von Größenordnungen.

Aktuelle Fassung. ich denke mal ich bin fertig.

Achja, der Android-Chatclient Jabiru hat als History-Store auch eine SQLite-Datenbank mit sehr ähnlichem Schema. Ich denk das sollte ziemlich trivial anzupassen sein. Werd ich vielleicht bei Langeweile mal machen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Schau dir mal http://www.sqlite.org/inmemorydb.html an (den zweiten Abschnitt mit Temporary Databases). Die sind vergleichbar mit In-Memory-Datenbanken, können aber nach getaner Arbeit verschoben/umbenannt/... werden.

Ansonsten kann man SQLite noch per PRAGMA-Statements (eine SQLite-SQL-Erweiterung) kontrolliere: http://www.sqlite.org/pragma.html. Hier sind besonders interessant `cache_size` und `synchronous`.
Antworten