<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Database on hdknr blog</title><link>https://hdknr.github.io/blogs/tags/database/</link><description>Recent content in Database on hdknr blog</description><generator>Hugo -- 0.157.0</generator><language>ja</language><lastBuildDate>Mon, 08 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://hdknr.github.io/blogs/tags/database/index.xml" rel="self" type="application/rss+xml"/><item><title>SQLite の「unable to open database file」が高負荷時刻に散発する問題を WAL 化で根治した話</title><link>https://hdknr.github.io/blogs/posts/2026/06/sqlite-wal-unable-to-open/</link><pubDate>Mon, 08 Jun 2026 00:00:00 +0000</pubDate><guid>https://hdknr.github.io/blogs/posts/2026/06/sqlite-wal-unable-to-open/</guid><description>&lt;h1 id="sqlite-のunable-to-open-database-fileが高負荷時刻に散発する問題を-wal-化で根治した話"&gt;SQLite の「unable to open database file」が高負荷時刻に散発する問題を WAL 化で根治した話&lt;/h1&gt;
&lt;p&gt;ある自立型トレーディングシステムの運用中に、SQLite が &lt;code&gt;OperationalError: unable to open database file&lt;/code&gt; を散発的に投げる慢性バグを追い詰めて修正した記録です。「ディスクは空いている」「ファイルは存在する」のにエラーが出る、という一見矛盾した現象の正体と、その根治・緩和の二段構えの対策をまとめます。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="wal-とは"&gt;WAL とは?&lt;/h2&gt;
&lt;p&gt;本題に入る前に、今回のキーになる &lt;strong&gt;WAL（Write-Ahead Logging）&lt;/strong&gt; を簡単に押さえておきます。&lt;/p&gt;
&lt;p&gt;SQLite には書き込み中のクラッシュからデータを守るための「ジャーナル方式」が複数あり、&lt;code&gt;journal_mode&lt;/code&gt; PRAGMA で切り替えます。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;delete&lt;/code&gt;（デフォルト）&lt;/strong&gt; — ロールバックジャーナル方式。トランザクションを開始するたびに &lt;code&gt;元DB-journal&lt;/code&gt; というファイルを&lt;strong&gt;新規作成&lt;/strong&gt;して変更前の内容を退避し、コミット時に削除する。書き込み中は DB 本体を直接書き換えるため、&lt;strong&gt;読み取りと書き込みが互いをブロック&lt;/strong&gt;する。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WAL&lt;/code&gt;&lt;/strong&gt; — 先行書き込みログ方式。変更を DB 本体ではなく追記専用の &lt;code&gt;元DB-wal&lt;/code&gt; ファイルに&lt;strong&gt;追記&lt;/strong&gt;していき、後で「チェックポイント」で本体に反映する。&lt;code&gt;-wal&lt;/code&gt; と &lt;code&gt;-shm&lt;/code&gt;（共有メモリインデックス）は一度作られたら使い回されるため、&lt;strong&gt;トランザクション毎のファイル新規作成が発生しない&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;WAL の主な利点:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特徴&lt;/th&gt;
&lt;th&gt;効果&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;読み書きが互いをブロックしない&lt;/td&gt;
&lt;td&gt;reader はトランザクション中の writer を待たずに読める（その逆も）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ジャーナルファイルを毎回作らない&lt;/td&gt;
&lt;td&gt;ファイル作成のオーバーヘッドと競合がなくなる&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;書き込みが概ね高速&lt;/td&gt;
&lt;td&gt;fsync 回数を減らせる（特に &lt;code&gt;synchronous=NORMAL&lt;/code&gt; 併用時）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;WAL が向いているケース&lt;/strong&gt;: 読み取りが多く・書き込みもそれなりにある、同一ホスト上の単一プロセス／複数プロセスからのアクセス。今回のように「書き込みデーモン 1 つ＋複数の reader」という構成は典型的な適用例です。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WAL の注意点&lt;/strong&gt;: ① ネットワーク越しのファイルシステム（NFS など）では共有メモリが使えず非対応、② in-memory DB では効かない、③ &lt;code&gt;-wal&lt;/code&gt; / &lt;code&gt;-shm&lt;/code&gt; ファイルが DB 本体と併存するため、バックアップは単純な &lt;code&gt;cp&lt;/code&gt; ではなく専用 API（後述）を使う必要がある。&lt;/p&gt;</description></item></channel></rss>