Aller au contenu

SQLite : sauvegarde et maintenance

Un fichier SQLite se sauvegarde en le copiant, à condition qu’aucune écriture ne soit en cours. Pour une base utilisée, la copie à chaud doit passer par SQLite. Les exemples utilisent boutique.db.

Fenêtre de terminal
sqlite3 boutique.db ".backup 'sauvegarde.db'"
sqlite3 boutique.db ".backup 'sauvegarde-$(date +%F).db'"

.backup produit une copie cohérente même si l’application continue d’écrire.

Fenêtre de terminal
sqlite3 boutique.db "VACUUM INTO 'copie-compacte.db';"

Crée une copie défragmentée, cohérente, souvent plus petite. Le fichier de destination ne doit pas exister.

Fenêtre de terminal
sqlite3 boutique.db .dump | gzip > boutique-$(date +%F).sql.gz

Format lisible, indépendant de la version de SQLite et portable (voir Import et export).

Fenêtre de terminal
cp sauvegarde.db boutique.db # application arrêtée
gunzip -c boutique-2026-10-05.sql.gz | sqlite3 restauree.db

Toujours restaurer d’abord dans un nouveau fichier pour vérifier le contenu :

Fenêtre de terminal
sqlite3 restauree.db "PRAGMA integrity_check; SELECT COUNT(*) FROM clients;"
PRAGMA integrity_check; -- affiche « ok » si le fichier est sain
PRAGMA quick_check; -- version plus rapide
PRAGMA foreign_key_check; -- lignes qui violent une clé étrangère

Par défaut, une écriture bloque les lectures. Le mode WAL (journal d’écriture anticipée) permet aux lectures de continuer pendant une écriture et améliore les performances :

PRAGMA journal_mode = WAL; -- réglage persistant, enregistré dans le fichier
PRAGMA busy_timeout = 5000; -- attend jusqu'à 5 s au lieu d'échouer avec « database is locked »
PRAGMA synchronous = NORMAL; -- compromis sûr en mode WAL

En mode WAL, SQLite crée à côté de la base les fichiers boutique.db-wal et boutique.db-shm : ils font partie de la base et ne doivent pas être supprimés quand l’application tourne. PRAGMA wal_checkpoint(TRUNCATE); reporte le journal dans le fichier principal.

journal_mode et synchronous doivent être définis à chaque ouverture si on ne veut pas dépendre de la valeur enregistrée ; busy_timeout est propre à chaque connexion.

VACUUM; -- reconstruit le fichier (libère l'espace des suppressions)
PRAGMA optimize; -- met à jour les statistiques si utile (à lancer avant de fermer)
ANALYZE; -- statistiques pour l'optimiseur
PRAGMA page_count;
PRAGMA page_size;
PRAGMA freelist_count; -- pages libres récupérables par VACUUM

VACUUM demande, pendant l’opération, de la place libre égale à la taille de la base et la verrouille en écriture : le lancer hors heures d’activité.

Fenêtre de terminal
sqlite3 boutique.db ".recover" | sqlite3 recuperee.db

.recover extrait ce qui est lisible d’un fichier corrompu. Vérifier ensuite recuperee.db avec PRAGMA integrity_check;. Si la base avait été analysée (ANALYZE), des messages d’erreur sur sqlite_stat1 peuvent apparaître pendant la récupération : sans gravité, relancer ANALYZE; ensuite pour recréer les statistiques.

Script /usr/local/bin/sauvegarde-sqlite.sh :

#!/usr/bin/env bash
set -euo pipefail
BASE="/srv/application/boutique.db"
DEST="/var/backups/sqlite"
mkdir -p "$DEST"
sqlite3 "$BASE" ".backup '$DEST/boutique-$(date +%F_%H%M).db'"
# Conserve 14 jours
find "$DEST" -name "boutique-*.db" -mtime +14 -delete
Fenêtre de terminal
sudo chmod 750 /usr/local/bin/sauvegarde-sqlite.sh
crontab -e
30 2 * * * /usr/local/bin/sauvegarde-sqlite.sh >> /var/log/sauvegarde-sqlite.log 2>&1

Copier ensuite les sauvegardes hors du serveur.

Fenêtre de terminal
chmod 640 boutique.db
chown application:application boutique.db

Le dossier contenant la base doit aussi être accessible en écriture par l’application : SQLite y crée des fichiers temporaires et de journal.

Symptôme Piste
database is locked Écriture simultanée : mode WAL et busy_timeout, transactions courtes
database disk image is malformed Fichier corrompu : restaurer une sauvegarde, ou tenter .recover
disk I/O error Disque plein, ou dossier non accessible en écriture
Le fichier -wal devient très gros Une lecture longue empêche le point de contrôle : fermer les lectures, PRAGMA wal_checkpoint(TRUNCATE);