ByteScope

SQLite データベースファイル形式

SQLite のデータベースファイル。単一ファイルで完結する組み込み SQL データベース。

MIME タイプ
application/vnd.sqlite3
拡張子
.sqlite, .db, .sqlite3
カテゴリ
データ・データベース

マジックナンバー(ファイル署名)

0x0000000053514C69746520666F726D6174203300SQLite format 3·'SQLite format 3\0' header

SQLite データベース形式について

SQLite のデータベースは、すべて同じ大きさの固定サイズページを並べたもので、1 ページ目の先頭 100 バイトがファイル全体を説明するヘッダに割り当てられています。それ以外はすべて(テーブルもインデックスもスキーマ自身も)そのページで組んだ B-tree です。スキーマにしても、他と同じように 1 ページ目に置かれた sqlite_schema というテーブルにすぎません。この均質さが形式の安定性を支えていて、2004 年に SQLite 3.0 が書いたファイルは今日でも開きますし、プロジェクトは 2050 年まで読めるようにすると公言しています。

ヘッダーの構造(バイト単位)

オフセット長さフィールド意味
016Header stringASCII の 'SQLite format 3' に NUL バイトが 1 つ続く、ちょうど 16 バイト。3 はライブラリのバージョンではなくファイル形式の世代で、2004 年から変わっていません。
162Page sizeビッグエンディアンで、デスクトップで出会う数少ないビッグエンディアンのフィールドの 1 つです。512 から 32768 までの 2 のべき乗、または 2 バイトに収まらないため値 1 で 65536 を表します。今どきの既定は 4096 なので、たいてい 10 00 と読めます。
181File format write version1 なら従来のロールバックジャーナル、2 なら write-ahead logging。WAL モードのデータベースは相棒の -wal と -shm が揃っている必要があります。稼働中のデータベースから .db だけをコピーすると直近のコミットを失うのはこのためです。
191File format read version1 か 2 で意味は上と同じ。2 より大きい値は「このファイルは理解できない何かを使っている」と古いライブラリに伝えるもので、その場合は推測せず拒否しなければなりません。
201Reserved space per page各ページの末尾に未使用として残すバイト数で、通常は 0 です。SEE のような暗号化拡張は、ページごとの nonce と認証タグを置くためにここを設定します。開けないファイルでここが非ゼロなら、それが理由です。
211Maximum embedded payload fraction64 でなければなりません。調整可能にする気で作られながら結局そうならなかったつまみなので、これ以外の値は珍しい設定ではなくヘッダの破損を意味します。
221Minimum embedded payload fraction32 でなければなりません。上下のバイトと合わせた 64、32、32 という並びが、このヘッダで一番安上がりな整合性チェックです。
231Leaf payload fraction32 でなければなりません。固定されている理由は上と同じ歴史的事情で、設定可能にするつもりが最後までそうならなかったのです。
244File change counterファイルを変更するトランザクションのたびに増えます。読む側はこれでキャッシュしたページが古くなったことに気づけるので、前回見たときからデータベースに書き込みがあったかを確かめる一番手早い方法でもあります。
284Database size in pagesヘッダに書かれたサイズです。信用してよいのはオフセット 92 の version-valid-for と一致するときだけで、そうでなければ本当のサイズはファイル長 ÷ ページサイズです。このフィールドを維持しない古いライブラリが書き込んだ可能性があるからです。
324First freelist trunk page未使用ページのリストが始まるページ番号、無ければ 0。削除された行のページはファイルを縮めるのではなくこのリストに積まれます。VACUUM を実行するまでデータベースが小さくならないのはそのためです。
364Freelist page countそのリストに乗っているページ数。データベースの規模に対してこの値が大きければ、大量に削除して領域を抱えたままのファイルだという印であり、同時に削除済みの行が hex エディタでまだ拾える状態だという印でもあります。
404Schema cookieスキーマが変わるたびに増えます。プリペアドステートメントはコンパイル時の値を覚えていて、この値が動くと自動的に再コンパイルされます。接続を開いたまま ALTER TABLE を打てるのはこの仕組みのおかげです。
444Schema format number1 から 4。現行は 4 で、2006 年以降の既定です。DESC インデックスや真偽値リテラルはこれで有効になります。知らない形式番号を見た古いライブラリは、読み違えるのではなくファイルを拒否します。
484Default page cache sizePRAGMA default_cache_size が設定する、ページキャッシュへの提案値です。あくまで助言でありライブラリは無視してかまいません。最近のバージョンはおおむね無視します。
524Largest root b-tree pageauto-vacuum または incremental-vacuum のときだけ非ゼロで、ポインタマップを維持できるよう最大のルートページを記録します。ゼロなら、そのデータベースが自力で縮むことはありません。
564Text encoding1 が UTF-8、2 が UTF-16 リトルエンディアン、3 が UTF-16 ビッグエンディアン。データベース作成時に 1 度だけ決まり、以後変更できません。実質すべての実装が書くのは UTF-8 で、ここを取り違えて文字列を読むと文字化けだらけのデータベースになります。
604User versionSQLite 自身は触らず、PRAGMA user_version で読み書きします。アプリはこれをスキーマ移行のカウンタとして使うので、どのバージョンのアプリが書いたデータベースかを突き止めたいときには、ファイル中で最も役に立つ 4 バイトになります。
644Incremental vacuum modeincremental-vacuum が有効なら非ゼロ。意味を持つのは、オフセット 52 の最大ルートページも非ゼロのときだけです。
684Application IDPRAGMA application_id が設定する値で、プログラムがこのデータベースファイルを自分の形式だと名乗るためのものです。アプリがちゃんと設定していれば、判定器が「これは SQLite です」ではなく「これは Firefox の places データベースです」と言えるようになります。
7220Reserved for expansionゼロでなければならない 20 バイト。20 年間ゼロのままなので、ここに非ゼロが並んでいれば、何かがヘッダを上書きした確かな証拠になります。
924Version valid for number下のバージョン番号が最後に書かれたときの変更カウンタの値です。オフセット 24 の変更カウンタと一致しないなら、古いライブラリがファイルを変更したということであり、オフセット 28 のヘッダ内サイズを信用してはいけません。
964SQLITE_VERSION_NUMBER最後にこのファイルを書いたライブラリのバージョンで、メジャー × 100 万 + マイナー × 1000 + パッチとして符号化されています。0x002E8DF8 は 3051000、つまり SQLite 3.51.0。どのビルドが最後にこのデータベースを触ったかがこの 4 バイトで正確に分かります。

似た形式との見分け方

紛らわしい形式見分け方
WAL mode先頭 16 バイトは完全に同一で、違いはオフセット 18 と 19 の 2 バイトが 1 ではなく 2 になっていることだけです。これが重要なのは、最新のコミット済みデータが .db ファイルの中にまったく無い可能性があるからです。それは相棒の -wal ファイルの中にあります。データベースだけをコピーすると、トランザクションが黙って失われます。先にチェックポイントを打つか、3 つのファイルをまとめてコピーしてください。
Encrypted SQLiteSQLCipher などはヘッダを含むファイル全体を暗号化するので、オフセット 0 は乱数めいたバイト列になり、どの判定器も SQLite とは呼びません。SEE 拡張は逆の方針を取り、ヘッダは読める状態のまま、オフセット 20 の予約領域バイトを非ゼロにします。SQLite と判定されるのに開けないファイルは、オフセット 20 を確認する価値があります。
OLE2 / CFB「1 ファイルの中のファイルシステム」という汎用形式が 2 つ。SQLite は読める ASCII 16 バイトで始まり、Compound File Binary コンテナは D0 CF 11 E0 A1 B1 1A E1 で始まります。どちらも固定サイズページを使い、フリーリストを持ち、書き込み途中の中断に弱いのも同じ。ただし SQLite の形式は公開・版管理され、フィールド単位まで文書化されています。CFB は最初の 15 年間そうではありませんでした。
Parquet「データを 1 ファイルで配るならどっち」という話になると必ず出てくる組み合わせです。Parquet は列指向・不変で、両端に 'PAR1' の印が付きます。SQLite は行指向・トランザクション対応で、その場で更新できます。10 億行の 1 列を走査するなら Parquet の圧勝、インデックスや結合、行の書き戻しが要るなら SQLite の勝ちです。

よくある壊れ方

  • -wal や -journal のファイルを失った。データベース本体は完全に無傷なのに読み込みが失敗したり、黙ってロールバックされたりします。コピーした時点でトランザクションが飛んでいたからです。これは .db の破損ではなく不完全なコピーであり、人が SQLite のデータベースを壊す方法として断然多いパターンです。
  • 書き込み中のファイルをコピーした。コミットは複数のページに触れるので、トランザクションの途中でスナップショットを取ると、古いページと新しいページが混ざった、どの時点にも存在しなかった状態が撮れてしまいます。ヘッダは完璧にパースでき、ページ数ももっともらしく、B-tree をたどっていくと別のテーブルのページに落ちます。cp ではなくバックアップ API か VACUUM INTO を使ってください。
  • テキストモード転送、あるいはエディタがファイルを書き直した。多バイトのフィールドはすべてバイナリで、ヘッダの ASCII 部分には 0D 0A が含まれていないので、そこだけ無傷で残り、それ以降のページ境界が全部ずれます。ファイルは依然 SQLite と識別され、1 ページ目から先が読めません。
  • ダウンロードの途中切れ。オフセット 28 のヘッダは、ファイルに収まりきらないページ数を宣言することになります。SQLite が確認しているのはまさにこれで、宣言されたサイズと、ファイル長 ÷ オフセット 16 のページサイズを比べます。短くなったファイルでも読み取り専用で開けることがあり、切断より前にページが収まったテーブルはそのまま使えます。
  • 他のプログラムがヘッダのバイトを上書きした。オフセット 21、22、23 の 3 つの定数は 64、32、32 でなければならず、オフセット 72 からの 20 バイトはゼロでなければなりません。踏み荒らされたヘッダを検出する一番安上がりなテストがこれで、その名前を自分のものだと思い込んだ何かが書き込んだ場合を捕まえられます。

この形式の現在地

SQLite は世界で最も広く配備されているデータベースエンジンであり、その座を降りる気配もありません。Android と iOS の全端末、主要ブラウザ、macOS、無数のデスクトップアプリ、そして大量の組み込みファームウェアが、状態を SQLite のファイルに置いています。データに構造があり、問い合わせが必要で、1 台のマシンに収まるなら、まず第一候補です。アプリの設定、キャッシュ、メッセージ履歴、オフラインストア、ローカルの集計。サーバーも設定もネットワークも要らずに、本物のトランザクションと本物の SQL が手に入ります。向いていないのは複数のマシンから同時に書き込む場面で、ロックがファイルベースなのでネットワークファイルシステムでは破綻します。そこが PostgreSQL や MySQL の出番の境界線です。近年はデータベースというよりアプリのファイル形式としての採用も増えました。1 つの .sqlite がプロジェクト一式を運び、全体を書き直さずにその場で更新でき、保存の途中でクラッシュしても壊れにくい。自作のバイナリ形式ではまず得られない性質です。形式の安定性が明文化されていること、そしてテストスイートがライブラリ本体より大きいことを考えれば、アーカイブを賭ける相手としては妥当な選択です。

SQLite データベースファイルをこのサイトで開く

どれもブラウザ内で動きます。ファイルが端末から出ることはありません。

関連する形式

SQLite データベースと混同しやすい形式です。先頭バイトを見比べてください。

形式先頭バイト拡張子
Parquet50 41 52 31.parquet
OLE2 / CFBD0 CF 11 E0 A1 B1.doc

よくある質問

ファイルのマジックナンバーとは何ですか?

ファイル先頭の数バイトで、名前が何であろうとその形式を示すものです。PNG は必ず 89 50 4E 47 で始まり、ZIP は 50 4B 03 04 で始まります。OS もブラウザも file コマンドも、拡張子を信用せずこのバイト列を読みます。だからファイル名を変えても中身の正体は変わりません。

マジックナンバーを自分で確認する方法は?

macOS や Linux なら xxd -l 16 ファイル名 で先頭 16 バイトが表示されます。Windows なら PowerShell で Format-Hex -Path ファイル名 -Count 16 です。あるいはこのサイトのファイル形式判別ツールにドロップすれば、ローカルでバイト列を読んで形式を教えてくれます。アップロードはありません。

2 つの形式が同じマジックナンバーを持つのはなぜ?

一方が他方の上に作られているからです。docx、xlsx、pptx、apk、jar、epub はすべて中身が ZIP アーカイブなので ZIP の署名で始まり、区別するには内部のエントリを見る必要があります。Java の class ファイルと macOS のユニバーサルバイナリはどちらも CA FE BA BE で始まり、直後のフィールドで見分けます。

マジックナンバーがまったくないファイルもある?

あります。XML、HTML、JSON、SVG、CSV といったテキストベースの形式には固定のバイト署名がないため、構造から判別します。先頭の <?xml 宣言、<svg 要素、あるいは { に続く引用符付きのキーなどです。これは確定ではなく推測なので、このリファレンスではそうした形式をプローブ判別として示しています。

マジックナンバーが一致すればそのファイルは安全?

いいえ。わかるのは形式であって、中身が無害かどうかではありません。正規の PDF や docx でも悪意のあるペイロードを含んでいることがあります。特に拡張子とバイト列が食い違うときに真の形式を知るのは有用な第一段階ですが、マルウェアスキャンではありません。

SQLite データベースかもしれないファイルをお持ちですか?ファイル形式判別ツールで調べる — マジックナンバーをローカルで読み取ります。アップロードは一切ありません。またはすべての形式を見る。