PRAGMA journal_mode (WAL) în SQLite

PRAGMA și configurare SQLite 3.7.0 (modul WAL)

Alege cum protejează SQLite datele la scriere. Modul WAL permite citiri în timp ce altcineva scrie și este alegerea uzuală pentru aplicații.

Sintaxă
PRAGMA journal_mode;
PRAGMA journal_mode = DELETE | TRUNCATE | PERSIST | MEMORY | WAL | OFF;
PRAGMA wal_checkpoint;

Ce face PRAGMA journal_mode (WAL)

Ca să nu strice baza dacă programul se oprește în mijlocul unei scrieri, SQLite folosește un jurnal. Implicit (DELETE), înainte de a modifica fișierul copiază paginile vechi într-un fișier baza.db-journal, pe care îl șterge la final.

În modul WAL (write-ahead log), modificările sunt adăugate întâi într-un fișier baza.db-wal, iar fișierul principal rămâne neschimbat până la un checkpoint. Avantajul: cititorii nu blochează scriitorul și scriitorul nu blochează cititorii, iar scrierile mici sunt de obicei mai rapide. Rămâne valabil: un singur scriitor odată.

Modul WAL se salvează în fișierul bazei, deci îl setezi o singură dată. Lângă bază apar fișierele -wal și -shm, care fac parte din bază cât timp e deschisă. WAL nu funcționează pe sisteme de fișiere în rețea (NFS, partajări SMB). O bază în memorie are mereu modul memory.

Parametri

Parametru Descriere
DELETE Implicit: jurnal separat, șters după fiecare tranzacție.
WAL Jurnal cu scriere în avans: citiri și o scriere în paralel. Persistent.
TRUNCATE / PERSIST Ca DELETE, dar golesc sau marchează jurnalul în loc să îl șteargă.
MEMORY / OFF Jurnal în memorie sau deloc: o oprire bruscă poate strica baza.

Exemple

Exemplul 1: Trecerea unei baze în modul WAL

O bază nou creată pornește în modul delete. Setarea întoarce noul mod, wal. După o scriere, lângă magazin.db apar fișierele -shm și -wal (comanda .shell rulează ls din sqlite3).

.open magazin.db
PRAGMA journal_mode;
PRAGMA journal_mode = WAL;

CREATE TABLE vanzari (oras TEXT, suma INTEGER);
INSERT INTO vanzari VALUES ('Iași', 1200), ('Cluj', 900);
.shell ls magazin.db*

Rezultat

╭──────────────╮
│ journal_mode │
╞══════════════╡
│ delete       │
╰──────────────╯
╭──────────────╮
│ journal_mode │
╞══════════════╡
│ wal          │
╰──────────────╯
magazin.db
magazin.db-shm
magazin.db-wal

Exemplul 2: Checkpoint manual

wal_checkpoint(TRUNCATE) mută paginile din -wal în fișierul principal și golește jurnalul. Rezultatul: busy (0 = nu a fost blocat), paginile din jurnal și paginile mutate; după TRUNCATE jurnalul este gol, deci ultimele două sunt 0. Implicit, SQLite face checkpoint singur când jurnalul trece de 1000 de pagini.

.open magazin.db
PRAGMA journal_mode = WAL;
CREATE TABLE vanzari (oras TEXT, suma INTEGER);
INSERT INTO vanzari VALUES ('Iași', 1200);

PRAGMA wal_checkpoint(TRUNCATE);
PRAGMA wal_autocheckpoint;

Rezultat

╭──────────────╮
│ journal_mode │
╞══════════════╡
│ wal          │
╰──────────────╯
╭──────┬─────┬──────────────╮
│ busy │ log │ checkpointed │
╞══════╪═════╪══════════════╡
│    0 │   0 │            0 │
╰──────┴─────┴──────────────╯
╭────────────────────╮
│ wal_autocheckpoint │
╞════════════════════╡
│               1000 │
╰────────────────────╯

Exemplul 3: O bază în memorie

Pentru :memory:, jurnalul este mereu în memorie, iar cererea de WAL este ignorată.

PRAGMA journal_mode;
PRAGMA journal_mode = WAL;

Rezultat

╭──────────────╮
│ journal_mode │
╞══════════════╡
│ memory       │
╰──────────────╯
╭──────────────╮
│ journal_mode │
╞══════════════╡
│ memory       │
╰──────────────╯

Greșeli frecvente

  • Copiezi doar fișierul .db al unei baze în WAL cât timp e deschisă. Ultimele modificări pot fi încă în -wal; folosește VACUUM INTO sau .backup.
  • Ștergi fișierele -wal și -shm crezând că sunt temporare. Fișierul -wal poate conține tranzacții confirmate care nu au ajuns încă în bază.
  • Pui baza în WAL pe un disc din rețea. Modul WAL are nevoie de memorie partajată pe aceeași mașină; pe NFS sau SMB rămâi la DELETE.

Comenzi înrudite

  • BEGIN, COMMIT, ROLLBACK: Grupează mai multe modificări într-o tranzacție: fie se salvează toate cu COMMIT, fie niciuna cu ROLLBACK.
  • VACUUM: Reconstruiește fișierul bazei de date: eliberează spațiul rămas după ștergeri și, cu INTO, face o copie compactă.
  • .open: Închide baza curentă și deschide (sau creează) alt fișier de bază de date, fără să ieși din sqlite3.
  • PRAGMA integrity_check: Verifică dacă fișierul bazei de date este întreg: paginile, indexurile și constrângerile. Răspunde „ok” dacă totul e în regulă.