wake-up-neo.net

SQLite3-Datenbank oder -Datenträger ist voll/Das Image der Datenbankfestplatte ist fehlerhaft

Meine Datenbank ist ungefähr 25 MB groß und ich habe überprüft, dass sich der Benutzername und die Dateiberechtigungen seit Monaten nicht geändert haben. Ich habe ein Problem, bei dem Abfragen aufgrund einer "Datenbank oder Festplatte ist voll" fehlschlagen und dann manchmal das Problem "Datenbankdatenträger-Image ist fehlerhaft".

Wenn ich das nicht falsch lese, ist meine Festplatte nicht annähernd voll (dies ist ein Ubuntu-Server, 9.10, falls es einen Unterschied macht)

Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1             19610300   2389596  16224560  13% /
udev                     10240       128     10112   2% /dev
none                    254136         0    254136   0% /dev/shm
none                    254136        36    254100   1% /var/run
none                    254136         0    254136   0% /var/lock
none                    254136         0    254136   0% /lib/init/rw

Als Test habe ich gerade eine Aktion durchgeführt, die eine neue Platte hinzugefügt hat, und das ist in Ordnung. Ich versuche herauszufinden, ob bestimmte Aktionen fehlschlagen. Nach dem Einfügen (und Überprüfen, dass es vorhanden ist) hat sich jedoch die Anzahl der Bytes auf der Festplatte für die Datenbank nicht geändert (weder nach oben noch nach unten).

Die Verwendung des Befehlszeilenhilfsprogramms führt zu Folgendem, was spektakulär ausfällt :)

SQLite version 3.6.12
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> pragma integrity_check;
*** in database main ***
On tree page 2 cell 0: 2nd reference to page 26416
On tree page 2 cell 1: 2nd reference to page 26417
On tree page 2 cell 2: 2nd reference to page 26434
On tree page 2 cell 3: 2nd reference to page 26449
On tree page 2 cell 4: 2nd reference to page 26464
On tree page 2 cell 5: 2nd reference to page 26358
On tree page 2 cell 6: 2nd reference to page 26494
On tree page 2 cell 7: Child page depth differs
On tree page 2 cell 8: 2nd reference to page 26190
On tree page 2 cell 8: Child page depth differs

... etc., etc. ...

Irgendwelche Ideen, wo ich als nächstes suchen sollte? Gibt es ein Problem mit der maximalen Anzahl von Zeilen in einer Tabelle oder so etwas? Ich habe etwas über die maximalen Werte von SQLite3 gelesen, und nichts in meiner Datenbank steht ihnen, soweit ich das beurteilen kann, nahe.

Ich habe mir dann meine täglichen Sicherungen angesehen und sehe, dass sich die Dateigröße der Datenbank für 3-4 Tage nicht geändert hat - sehr seltsam. Ich habe eine Sicherungskopie der Datenbank vor dem Zeitpunkt wiederhergestellt, zu dem sie sich nicht in der Dateigröße geändert hat, und immer noch merkwürdige Probleme bekommen.

Ich denke, ich muss (1) von einem älteren Backup wiederherstellen und (2) meine Rails-Migrationen erneut ausführen, um das Problem zu beheben.

47
jefflunt

Ein paar Dinge zu beachten:

  • SQLite3-DB-Dateien wachsen in etwa um ein Vielfaches der DB-Seitengröße und werden nicht verkleinert, es sei denn, Sie verwenden VACUUM. Wenn Sie einige Zeilen löschen, wird der freigegebene Speicherplatz intern markiert und in späteren Einfügungen wiederverwendet. Daher führt eine Einfügung häufig nicht zu einer Änderung der Größe der Sicherungs-DB-Datei.

  • Sie sollten keine herkömmlichen Sicherungstools für SQLite (oder andere Datenbanken) verwenden, da diese nicht die DB-Statusinformationen berücksichtigen, die für die Sicherstellung einer nicht beschädigten Datenbank wichtig sind. Insbesondere das Kopieren der DB-Dateien während einer Einfügetransaktion ist ein Notfallrezept ...

  • SQLite3 verfügt über ein API , das speziell zum Sichern oder Kopieren von Datenbanken verwendet wird, die gerade verwendet werden.

  • Und ja, es scheint, dass Ihre DB-Dateien beschädigt sind . Es könnte sich um einen Hardware-/Dateisystemfehler handeln. Oder haben Sie sie vielleicht kopiert, während sie verwendet wurden? Oder vielleicht ein Backup wiederhergestellt, das nicht ordnungsgemäß erstellt wurde?

24
thkala

Um eine beschädigte Datenbank zu reparieren, können Sie das Befehlszeilenprogramm sqlite3 verwenden. Geben Sie nach dem Festlegen der Umgebungsvariablen die folgenden Befehle in einer Shell ein:

cd $DATABASE_LOCATION
echo '.dump'|sqlite3 $DB_NAME|sqlite3 repaired_$DB_NAME
mv $DB_NAME corrupt_$DB_NAME
mv repaired_$DB_NAME $DB_NAME

Dieser Code half mir, eine SQLite-Datenbank wiederherzustellen, die ich als persistenten Speicher für Core Data verwende, und die beim Speichern den folgenden Fehler ausgegeben hat: 

Speichern nicht möglich: NSError 259 in Domäne NSCocoaErrorDomain {NSFilePath = mydata.db NSUnderlyingException = Fataler Fehler. Die Datenbank unter mydata.db ist korrupt. SQLite-Fehlercode: 11, 'Das Image der Datenbankfestplatte ist fehlerhaft'}

50
Pegolon

Ich verwende das folgende Skript zum Reparieren von fehlerhaften sqlite-Dateien:

#!/bin/bash

cat <( sqlite3 "$1" .dump | grep "^ROLLBACK" -v ) <( echo "COMMIT;" ) | sqlite3 "fix_$1"

Wenn eine SQLite-Datenbank fehlerhaft ist, können Sie immer noch einen Speicherauszug erstellen. Bei diesem Speicherauszug handelt es sich im Wesentlichen um viele SQL-Anweisungen, die die Datenbank neu erstellen.

Möglicherweise fehlen einige Zeilen im Speicherauszug (wahrscheinlich, weil sie beschädigt sind). Wenn dies der Fall ist, werden die INSERT-Anweisungen der fehlenden Zeilen durch einige Kommentare ersetzt und das Skript endet mit einer ROLLBACK TRANSACTION.

Was wir hier tun, ist, dass wir den Dump erstellen (missgebildete Zeilen werden ausgeschlossen) und wir ersetzen ROLLBACK durch ein COMMIT, sodass das gesamte Dump-Skript anstelle eines Rollbacks festgeschrieben wird.

Diese Methode hat mein Leben schon ein paar Mal gerettet.

18
Elmer

Um zu vermeiden, dass "Datenbank oder Datenträger voll ist", sollten Sie Folgendes tun, wenn Sie über viel RAM verfügen:

sqlite> pragma temp_store = 2;

Dadurch wird SQLite angewiesen, temporäre Dateien zu speichern. (Die Meldung "Datenbank oder Festplatte ist voll" bedeutet nicht, dass entweder die Datenbank voll ist oder dass die Festplatte voll ist! Dies bedeutet, dass das temporäre Verzeichnis voll ist.) Ich habe 256 GB RAM, aber nur 2 GB/tmp , das funktioniert also super für mich. Je mehr RAM Sie haben, desto größere Datenbankdateien können Sie bearbeiten.

Wenn Sie nicht viel RAM haben, versuchen Sie Folgendes:

sqlite> pragma temp_store = 1;
sqlite> pragma temp_store_directory = '/directory/with/lots/of/space';

temp_store_directory ist veraltet (was dumm ist, da temp_store nicht veraltet ist und temp_store_directory erfordert), seien Sie also vorsichtig im Code.

8
Phil Goetz

Ich habe gesehen, dass dies passiert, wenn die Datenbank beschädigt wird. Haben Sie versucht, sie in eine neue zu klonen? 

Safley-Kopie einer SQLite-Datenbank

Kopieren Sie eine SQLite-Datenbank sicher

Es ist ganz einfach, eine SQLite-Datenbank zu kopieren. Es ist weniger trivial zu tun dies auf eine Weise, die es nicht verfälschen wird. Hier ist wie:

Shell$ sqlite3 some.db
sqlite> begin immediate;
<press CTRL+Z>
Shell$ cp some.db some.db.backup
Shell$ exit
sqlite> rollback;

Dies gibt Ihnen ein schönes sauberes Backup, das sicher in einem richtigen Status, da in die Datenbank auf halbem Weg durch das Kopieren geschrieben wurde Prozess ist unmöglich.

5
Nix

bei der Verwendung von Google App Engine hatte ich dieses Problem. Aus irgendeinem Grund folgte ich, seitdem Google App Engine nie gestartet wurde.

$ echo '' > /tmp/appengine.apprtc.root/*.db

Um es zu beheben, musste ich es manuell tun:

$ sqlite3 datastore.db
sqlite> begin immediate;
<press CTRL+Z>
$ cp datastore.db logs.db

Führen Sie dann die Google App Engine mit Flag aus: 

$ dev_appserver.py --clear_datastore --clear_search_index

danach hat es endlich funktioniert.

1
YumYumYum

Während der App-Entwicklung habe ich festgestellt, dass die Nachrichten aus den häufigen und massiven INSERT- und UPDATE-Vorgängen stammen. Stellen Sie sicher, dass Sie mehrere Zeilen oder Daten in einem einzigen Vorgang einfügen und aktualisieren.

var updateStatementString : String! = ""

for item in cardids {
    let newstring = "UPDATE "+TABLE_NAME+" SET pendingImages = '\(pendingImage)\' WHERE cardId = '\(item)\';"
    updateStatementString.append(newstring)
}

print(updateStatementString)

let results = dbManager.sharedInstance.update(updateStatementString: updateStatementString)

return Int64(results)
0
Jorge Cardenas