SQLite beschleunigen...

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ich merke, das in PyHardLinkBackup das schreiben in die SQLite Datenbank doch das ganze so aus bremst, das es quasi unbrauchbar ist, wenn es zu viele kleine Dateien sind...

Also wenn sehr oft neue Datensätze in die SQLite Datenbank in kurzer Zeit geschrieben werden...

Wie kann ich das beschleunigen?

Ich nutzte die SQLite Datenbank ja mit dem Django ORM. Vielleicht kann ich an den "transactions" was ändern: https://docs.djangoproject.com/en/1.8/t ... nsactions/
Allerdings hab ich mich bisher um Transaktionen nicht gekümmert. Ich weiß nicht, ob beim einfügen eines Datensatzes, ein "flush" ausgelöst wird?!?

Eine Idee wäre evtl. eine zweite ":memory:" SQLite Datenbank zu nutzten und von Zeit zu Zeit (oder ganz am Ende) die Daten zu kopieren. Aber das verkompliziert alles und evtl. sind Daten weg, wenn es nicht bis zum Ende durchläuft. Auf der anderen Seite, stecken in der DB keine so super wichtigen Daten. Man kann sie schnell aus dem Dateisystem wieder rekonstruieren.

Oder: Statt ":memory:" könnte ich auch die Informationen estmal nicht in die DB schreiben, sondern nur in einem normalen dict() zwischenparken. Am Ende dann in die DB packen oder von Zeit zur zeit einfügen.

Oder: Die SQLite auf einer RAM-Disk legen, wäre denkbar. Aber unter Windows nicht mal eben so machbar.

Oder: Was anderes als SQLite nehmen, geht kaum, weil der der Installationsaufwand dann viel zu hoch ist.

Hat noch jemand Ideen?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich würde eigentlich erwarten, dass das DBMS mir das Caching abnimmt. Dass ist ja einer der Gründe, warum man so etwas einsetzt.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Vielleicht hilft dies hier:
The Boolean synchronous value controls whether or not the library will wait for disk writes to be fully written to disk before continuing. This setting can be different from the default_synchronous value loaded from the database. In typical use the library may spend a lot of time just waiting on the file system. Setting "PRAGMA synchronous=OFF" can make a major speed difference.
Quelle: http://www.codificar.com.br/blog/sqlite ... q/#pragmas

Hierzu sagt auch die Doku:
(...) some operations are as much as 50 or more times faster with synchronous OFF.
Quelle: http://www.sqlite.org/pragma.html#pragma_synchronous
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ah! Danke für die Tips!

Hab auch noch http://www.rkblog.rk.edu.pl/w/p/sqlite- ... nd-django/ gefunden...

Weiß jemand spontan, ob das aktuell noch der Best-Practise-Weg ist:

Code: Alles auswählen

from django.db.backends.signals import connection_created

def setup_sqlite(sender, connection, **kwargs):
    if connection.vendor == 'sqlite':
        cursor = connection.cursor()
        cursor.execute('PRAGMA foo = bar;')

connection_created.connect(setup_sqlite)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Bei Django würde ich auf jeden Fall mal ansetzen denn das macht ja im Normalzustand „autocommit“, also ein Commit nach jedem einzelnen Speichern. Da könntest Du Transaktionen für Verzeichnisse machen beispielsweise, oder alle x Dateien die verarbeitet wurden. Ich weiss es jetzt nicht aus dem Kopf, aber hat Django's ORM auch eine Methode um viele Model-Exemplare gleichzeitig hinzuzufügen? Da könnte man dann nämlich auf „prepared statements“/`executemany()` auf Datenbank- beziehungsweise Datenbankmodul hoffen, was bei SQLite ein bisschen was bringen sollte.

Bei der Frage nach dem wiederherstellen der Daten aus den Dateien auf der Platte wäre ich vorsichtig, denn man muss ja auch bedenken was eigentlich passiert wenn die Datenbank korrupt ist. *Merkst* Du das denn, und wenn ja woran? Gerade bei einer Backup-Software sollte man da noch ein bisschen paranoider sein. Die taugt ja nichts wenn man ohne es zu merken mit einer fehlerhaften Datenbank weiterarbeitet und am Ende dann Sachen nicht wiederhergestellt werden können.

In dem von Dir verlinkten Blogartikel wird erwähnt das jemand auf Reddit schrieb, Transaktionen würden einen Geschwindigkeitsschub bringen. Ich würde das ja als erstes ausprobieren, bevor Du anfängst Einstellungen zu machen, die an der Datenbankintegrität kratzen könnten.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

BlackJack hat geschrieben:Bei der Frage nach dem wiederherstellen der Daten aus den Dateien auf der Platte wäre ich vorsichtig, denn man muss ja auch bedenken was eigentlich passiert wenn die Datenbank korrupt ist. *Merkst* Du das denn, und wenn ja woran? Gerade bei einer Backup-Software sollte man da noch ein bisschen paranoider sein. Die taugt ja nichts wenn man ohne es zu merken mit einer fehlerhaften Datenbank weiterarbeitet und am Ende dann Sachen nicht wiederhergestellt werden können.
Also die Datenbank spielt noch keine große Rolle: Bisher wird die ja nur genutzt um identische Dateien zu finden. Also ist der SHA512 vom Dateiinhalt vorhanden um mit os.link() einen Hardlink zu machen.

Gut, wenn der SHA512 oder der Dateipfad manipuliert wäre, kommt murks raus. Aber nur dann, wenn es auch passt: z.B. wenn der SHA512 auf die falsche Datei zeigt.
Aber ich denke wahrscheinlicher ist, das kein os.link() gemacht wird, weil der Hash nicht zu finden ist (obwohl die Datei mit identischem Inhalt existiert) oder weil der Pfad falsch ist.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

BlackJack hat geschrieben:Ich weiss es jetzt nicht aus dem Kopf, aber hat Django's ORM auch eine Methode um viele Model-Exemplare gleichzeitig hinzuzufügen? Da könnte man dann nämlich auf „prepared statements“/`executemany()` auf Datenbank- beziehungsweise Datenbankmodul hoffen, was bei SQLite ein bisschen was bringen sollte.
Also es gibt "bulk_create" -> https://docs.djangoproject.com/en/1.8/r ... ulk_create

Aber das wäre keine gute Idee: So würde ich erst doppelte Einträgt finden, nachdem ein "bulk_create" gemacht wurde.

Es muß nach jedem neuen Eintragen einer Datei, diese auch direkt danach gefunden werden (Auch wenn es wohl nicht ganz so wahrscheinlich ist, das gleiche Dateien so oft hintereinander kommen werden)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Also settings.AUTOCOMMIT=False mit "PRAGMA temp_store = MEMORY;" und "PRAGMA synchronous=OFF" scheint keinen großen Unterschied zu machen...

https://github.com/jedie/PyHardLinkBack ... c5b917a4d4

War jetzt das schnellste zum mal eben probieren...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@jens
Mal ganz naiv gefragt: Wenn AUTOCOMMIT ausgeschaltet ist, benötigt die zwischengeschaltete Funktion dann nicht am Ende ein `commit()`, damit die geänderten Einstellungen auch ankommen? Hast du mal gegengeprüft, ob sich die Einstellungen für deine DB tatsächlich geändert haben?
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Naja, die unittests laufen durch. Von daher gehe ich mal schwer von aus :twisted:

Aufjeden Fall sieht man das auch mit diesen Einstellungen, fleißig die .journal Datei erzeugt und gelöscht werden... Hätte jetzt gedacht, das "PRAGMA temp_store = MEMORY;" bewirkt, das sie im RAM zwischengelagert werden...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@snafu: Man müsste dann wohl die Transaktionen von Django verwenden. Und natürlich nicht jede einzelne Änderung in eine Transaktion verpacken, denn dann hat man nichts gewonnen, sondern mehrere Änderungen in eine Transaktion stecken.

@jens: `temp_store` hat nichts mit dem Journal zu tun. Da gibt's auch ein Pragma für um das in den Speicher zu verlegen.

Edit: Das würde ich aber erst machen wenn Du sicher bist das Du nicht jede einzelne Änderung commitest. Wie hast Du das denn jetzt gelöst? Pro Verzeichnis oder nach x Dateien? Wie gross wäre in dem Fall x?
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ah:

PRAGMA schema.journal_mode = MEMORY

https://www.sqlite.org/pragma.html#pragma_journal_mode

Aber:
Note also that the journal_mode cannot be changed while a transaction is active.

Kann ich ja mal probieren...

Auf die schnelle das Transaktions-Verhalten zu ändern, klappte nicht.


EDIT: journal_mode = MEMORY bringt auch jeden Fall eine Beschleunigung.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab gesehen, das 'bedup' dieses setzt:

Code: Alles auswählen

    # Uncripple the SQL implementation
    cur.execute('PRAGMA foreign_keys = ON')

    # So that writers do not block readers
    # https://www.sqlite.org/wal.html
    cur.execute('PRAGMA journal_mode = WAL')
siehe: https://github.com/g2p/bedup/blob/7283d ... n__.py#L78

Vielleicht ist journal_mode = WAL schneller als journal_mode = MEMORY ???

Jemand Erfahrungen damit?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: WAL ist wie der Kommentar in dem Quelltext ja sagt, dafür da, dass Schreibzugriffe nicht mehr Lesezugriffe blockieren, also praktisch einsetzbar wenn viele Nutzer/Prozesse gleichzeitig auf die Datenbank zugreifen. Dafür werden mehr Dateien angelegt und ich glaube nicht das der zusätzliche Aufwand das ganze schneller macht. Das „viele Leser während des Schreibens“-Szenario hast Du doch auch gar nicht.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Das stimmt allerdings. Deswegen auch die Frage hier ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Es dürfte auch eine Überlegung wert zu schauen ob WAL irgendwelche Auswirkungen auf ACID hat.
Antworten