web-dev-qa-db-fra.com

La base de données ou le disque SQLite3 est saturé/l'image disque de la base de données est mal formée

Ma base de données fait environ 25 Mo et j'ai vérifié que le nom d'utilisateur y accédant, ainsi que les autorisations sur les fichiers, n'avaient pas changé depuis des mois. Je rencontre un problème d'échec de requête dû à un problème "la base de données ou le disque est saturé", puis parfois "l'image du disque de la base de données est mal formée".

À moins que je ne lise ceci incorrectement, mon disque n'est pas presque plein (il s'agit d'un serveur Ubuntu, 9.10, si cela fait une différence)

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

En guise de test, je viens de faire une action qui a ajouté un nouveau disque, et ça va. J'essaie de déterminer s'il y a un ensemble spécifique d'actions qui échouent. Cependant, après l'insertion (et la vérification de sa présence), le nombre d'octets sur le disque de la base de données n'a pas changé (ni vers le haut ni vers le bas).

L'utilisation de l'utilitaire de ligne de commande aboutit à quelque chose comme ce qui suit, qui échoue de manière spectaculaire :)

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. ...

Des idées sur l'endroit où je devrais regarder ensuite? Y at-il un problème avec le nombre maximal de lignes dans une table ou quelque chose? J'ai lu un peu sur les valeurs maximales de SQLite3, et rien dans ma base de données ne leur ressemble autant que je sache.

J'ai ensuite examiné mes sauvegardes quotidiennes et constaté que la taille du fichier de sauvegarde de la base de données n'avait pas changé depuis 3 ou 4 jours, ce qui est très étrange. J'ai restauré une copie de sauvegarde de la base de données d'avant le moment où la taille du fichier ne changeait pas, et j'obtenais toujours des problèmes étranges.

Je pense que je vais devoir (1) restaurer à partir d'une sauvegarde plus ancienne et (2) réexécuter mes migrations Rails pour y remédier.

47
jefflunt

Quelques points à considérer:

  • Les fichiers de base de données SQLite3 grossissent en gros par rapport à la taille de la page de base de données et ne se réduisent pas sauf si vous utilisez VACUUM. Si vous supprimez certaines lignes, l'espace libéré est marqué en interne et réutilisé dans des insertions ultérieures. Par conséquent, une insertion ne provoquera souvent pas de modification de la taille du fichier de base de données de sauvegarde.

  • N'utilisez pas les outils de sauvegarde traditionnels pour SQLite (ou toute autre base de données), car ils ne prennent pas en compte les informations d'état de la base de données essentielles pour garantir la sécurité de la base de données. Surtout, copier les fichiers de la base de données au milieu d’une transaction d’insertion est une recette pour un sinistre.

  • SQLite3 a un API spécialement conçu pour la sauvegarde ou la copie de bases de données en cours d'utilisation.

  • Et oui, il semble que vos fichiers de base de données soient corrompus . Ce pourrait être une erreur de matériel/système de fichiers. Ou peut-être les avez-vous copiées pendant leur utilisation? Ou peut-être restauré une sauvegarde qui n'a pas été correctement prise?

24
thkala

Pour réparer une base de données corrompue, vous pouvez utiliser l'utilitaire de ligne de commande sqlite3. Tapez les commandes suivantes dans un shell après avoir défini les variables d'environnement:

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

Ce code m'a aidé à récupérer une base de données SQLite que j'utilise comme magasin persistant pour Core Data et qui a généré l'erreur suivante lors de l'enregistrement: 

Impossible de sauvegarder: NSError 259 dans le domaine NSCocoaErrorDomain {NSFilePath = mydata.db NSUnderlyingException = Erreur fatale. La base de données sur mydata.db est corrompu. Code d'erreur SQLite: 11, 'l'image disque de la base de données est mal formée'}

50
Pegolon

J'utilise le script suivant pour réparer les fichiers sqlite mal formés:

#!/bin/bash

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

La plupart du temps, lorsqu'une base de données sqlite est mal formée, il est toujours possible d'effectuer un dump. Ce vidage est constitué de nombreuses instructions SQL qui reconstruisent la base de données.

Certaines lignes peuvent être absentes du dump (probablement parce qu'elles sont corrompues). Si tel est le cas, les instructions INSERT des lignes manquantes seront remplacées par des commentaires et le script se terminera par ROLLBACK TRANSACTION.

Nous faisons donc le dump (les lignes mal formées sont exclues) et nous remplaçons le ROLLBACK par un COMMIT afin que le script de dump entier soit validé au lieu d'être annulé.

Cette méthode m'a déjà sauvé la vie une centaine de fois\o /

18
Elmer

Pour éviter d’obtenir «la base de données ou le disque plein», essayez ceci si vous avez beaucoup de RAM:

sqlite> pragma temp_store = 2;

Cela indique à SQLite de mettre des fichiers temporaires en mémoire. (Le message "la base de données ou le disque est plein" ne signifie pas que la base de données est pleine ou que le disque est plein! Cela signifie que le répertoire temporaire est plein.) J'ai 256G de RAM mais seulement 2G de/tmp , donc cela fonctionne très bien pour moi. Plus vous avez de RAM, plus gros sont les fichiers de base de données avec lesquels vous pouvez travailler.

Si vous n'avez pas beaucoup de bélier, essayez ceci:

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

le répertoire temp_store_directory est obsolète (ce qui est idiot, puisque temp_store n'est pas obsolète et nécessite le répertoire temp_store_directory), soyez donc prudent de ne pas l'utiliser dans le code.

8
Phil Goetz

J'ai vu cela se produire lorsque la base de données est corrompue. Avez-vous essayé de la cloner dans une nouvelle? 

Safley copie une base de données SQLite

Copier en toute sécurité une base de données SQLite

Il est très facile de copier une base de données SQLite. C'est moins trivial à faire ceci d'une manière qui ne le corrompra pas. Voici comment:

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

Cela vous donnera une sauvegarde propre et agréable qui ne manquera pas d'être dans un bon état, depuis l’écriture dans la base de données à mi-chemin de votre copie processus est impossible.

5
Nix

lors de l'utilisation de Google App Engine, j'ai eu ce problème. Pour une raison quelconque, j'ai suivi depuis lors, Google App Engine n'a jamais démarré.

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

Pour résoudre ce problème, je devais le faire manuellement:

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

Et puis exécutez le moteur Google App avec l'indicateur: 

$ dev_appserver.py --clear_datastore --clear_search_index

après ça a finalement fonctionné.

1
YumYumYum

Lors du développement de l'application, j'ai constaté que les messages provenaient des opérations fréquentes et massives INSERT et UPDATE . Assurez-vous d'insérer et d'actualiser plusieurs lignes ou données en une seule opération.

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