SQLiteでWALモードを有効化して書き込み並行性とパフォーマンスを高める方法

SQLite Database Performance SQL
結論

全接続で busy_timeout を設定し、PRAGMA journal_mode=WAL; で並行性を向上させます。

-- SQLite公式仕様:並行性を向上させる PRAGMA 設定順序
-- 1. 接続直後にタイムアウト時間を設定 (コネクションごとに必須)
PRAGMA busy_timeout = 5000;

-- 2. WAL モードへ切り替え (DBファイルに永続保存)
PRAGMA journal_mode = WAL;

-- 3. 同期レベルの最適化 (必要に応じて)
PRAGMA synchronous = NORMAL;

SQLite公式仕様:従来ジャーナルと WAL モードの比較

SQLite公式ドキュメント(sqlite.org/wal.html)の規定通り、従来のロールバックジャーナルから WAL(Write-Ahead Logging)モードに変更することで動作モデルが根本的に変化します。

項目従来モード (journal_mode=DELETE)WAL モード (journal_mode=WAL)
読み書き並行性❌ 書き込み中は全読み取り(SELECT)がブロック◯ 複数の読み取りと1つの書き込みが同時実行可能
I/O パフォーマンス❌ 変更ごとにディスク全書き換え◯ WALファイルへ追記するため超高速
永続性接続ごとに毎回指定が必要◯ DBファイルへ永続保存(初回1回でOK)

実際に起こる障害:busy_timeout 設定漏れによる database is locked 事故

SQLiteでよくある勘違いが、PRAGMA journal_mode=WAL; さえ実行しておけば二度とロックエラーが起きないという誤解 です。

  1. journal_mode=WAL はDBファイルに永続記憶される が、
  2. PRAGMA busy_timeout=5000 は接続(Connection)ごとの使い捨て(Ephemeral)設定である

そのため、新しいコネクションを張り直した際に busy_timeout を実行し忘れると、他のプロセスが書き込みを行っている最中にアクセスした瞬間、待機(Retry)を行わずに SQLITE_BUSY: database is locked エラーを即座に投げてアプリケーションがクラッシュする障害 が発生します。


実装手順

  1. データベース接続(Connection)を開く処理(Prisma, Better-SQLite3, Drizzle等)のフックに PRAGMA busy_timeout = 5000; を組み込む
  2. その後 PRAGMA journal_mode = WAL; を発行する
  3. 本番環境の busy_timeout は 3000ms 〜 5000ms(3〜5秒)を確保し、一時的な書き込み競合を自動再試行で吸収させる