世界を動かす技術を、日本語で。

SQLiteのファイルフォーマット

2025年9月5日原文(sqlite.org)

概要

  • SQLiteデータベースファイル形式 の全体像解説
  • メインデータベースファイルジャーナル/WALファイル の役割
  • ページ構造ファイルヘッダー の詳細
  • 各種バージョン番号フリーページリスト の意味
  • スキーマフォーマット番号 の違いと互換性

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

  • SQLite のデータベース状態は、通常 単一のファイル (メインデータベースファイル)で管理
  • トランザクション中は ロールバックジャーナル または WALファイル に追加情報を保存
  • ホットジャーナルホットWALファイル はクラッシュ回復時にのみ必要となる特別ファイル
  • 本ドキュメントは 主にメインデータベースファイルのフォーマット を解説

ページ構造とサイズ

  • データベースファイルは ページ単位 で構成、ページサイズは 512~65536バイト の2のべき乗
  • ページサイズは、ファイル先頭から 16バイト目の2バイト整数値 で決定
  • ページ番号は 1から開始、最大4294967294ページ
  • 最小データベースサイズ は512バイト、最大は約281TB
  • 実運用では数KB~数GBが一般的、まれにTB級事例も存在

ページ種別

  • 各ページは以下いずれかの用途
    • B-treeページ(テーブル/インデックスの内部・リーフ)
    • フリーリストページ(トランク/リーフ)
    • ペイロードオーバーフローページ
    • ポインタマップページ
    • ロックバイトページ

データベースファイルヘッダー

  • ファイル先頭 100バイト がヘッダー領域
  • ビッグエンディアン 形式で多バイト値を格納
  • 主なフィールド(オフセット:サイズ:内容)
    • 0:16: "SQLite format 3\000"(マジックナンバー)
    • 16:2: ページサイズ(512~32768、または1で65536)
    • 18:1: ファイルフォーマット書き込みバージョン(1=レガシー, 2=WAL)
    • 19:1: ファイルフォーマット読み取りバージョン(1=レガシー, 2=WAL)
    • 20:1: 各ページ末尾の予約バイト数(拡張用、通常0)
    • 21:1/22:1/23:1: ペイロード比率(固定値64/32/32)
    • 24:4: ファイル変更カウンター
    • 28:4: データベースサイズ(ページ数)
    • 32:4: フリーリスト最初のページ番号
    • 36:4: フリーリスト合計ページ数
    • 40:4: スキーマクッキー(スキーマ変更時に更新)
    • 44:4: スキーマフォーマット番号(1~4)
    • 48:4: デフォルトページキャッシュサイズ
    • 56:4: テキストエンコーディング(1=UTF-8, 2=UTF-16le, 3=UTF-16be)
    • 60:4: ユーザーバージョン(PRAGMA user_versionで管理)
    • 64:4: インクリメンタルバキュームモードフラグ
    • 68:4: アプリケーションID(PRAGMA application_idで設定)
    • 72:20: 予約領域(ゼロ固定)
    • 92:4: version-valid-for番号
    • 96:4: SQLITE_VERSION_NUMBER

ページサイズの詳細

  • オフセット16の2バイト値でページサイズ決定
    • 512~32768 はビッグエンディアン整数
    • 65536バイト は0x00 0x01(ビッグエンディアンで1、マジックナンバー扱い)

ファイルフォーマットバージョン

  • 書き込み/読み取りバージョン (オフセット18,19)は将来拡張用
  • 現行SQLiteでは 1=ロールバックジャーナル、2=WAL
  • 読み取りバージョンが2超の場合は読み書き不可

ページ末尾の予約バイト

  • 拡張機能用に 各ページ末尾に追加バイト を予約可能
  • 通常0、SQLite Encryption Extension等で利用
  • ページ有効サイズは「ページサイズ-予約バイト数」
  • 有効サイズは 480バイト以上 必要(例:512バイトページなら予約最大32バイト)

ペイロード比率

  • 最大/最小/リーフペイロード比率 はそれぞれ 64/32/32 で固定
  • 本来はチューニング用だったが、現状は変更不可

ファイル変更カウンター

  • 4バイト整数(オフセット24) で管理
  • 他プロセスによる変更検知やキャッシュ無効化に利用
  • WALモードでは使用されない場合あり

データベースサイズの判定

  • オフセット28の4バイト値 が有効ならそれを使用
  • 無効時は実ファイルサイズ参照
  • 有効性判定は「変更カウンター」と「version-valid-for番号」が一致しているかで判断

フリーページリスト

  • 未使用ページ はフリーページリストで管理
  • オフセット32: 最初のフリーページ番号
  • オフセット36: フリーページ総数

スキーマクッキー

  • 4バイト整数(オフセット40) で管理
  • スキーマ変更時にインクリメント
  • プリペアドステートメントの再準備判別に利用

スキーマフォーマット番号

  • 4バイト整数(オフセット44)
  • 現在サポートされる番号は 1~4
    • 1: 最初期フォーマット
    • 2: ALTER TABLE ... ADD COLUMNサポート
    • 3: 非NULLデフォルト値付き追加カラムサポート
    • 4: インデックスDESCサポート等(デフォルト)
  • 新規ファイルは フォーマット4 が標準
  • sqlite3_db_config() のオプションでフォーマット1の作成も可能

この内容はSQLiteデータベースファイルの 物理構造理解や互換性管理エンジニアリング用途 に必須の情報。

Hackerたちの意見

ここのファイルフォーマットの内部構造がしっかりドキュメント化されてるのは本当にありがたいね。SQLiteの内部動作についてたくさんの情報がわかるし、読むことを強くおすすめするよ。実際、雨の日用にコピーを保存しておいたんだけど、すごく勉強になったし、将来SQLiteを使う際のデザイン決定にも影響を与えたよ。

フォーマット自体はアメリカの連邦標準で、変更できません。それには利点と欠点があります。 https://www.sqlite.org/locrsf.html

公式のSQLiteデータベースファイルフォーマットのページから。最大サイズのデータベースは4294967294ページ、1ページあたり65536バイト、つまり281,474,976,579,584バイト(約281テラバイト)になる。通常、SQLiteは自分の内部サイズ制限に達する前に、基盤となるファイルシステムやディスクハードウェアの最大ファイルサイズ制限に達しちゃうんだよね。

「通常」?確かに、単一のファイルシステムでこれだけのスペースを持つコンピュータが存在しないわけじゃないけど…実際に誰かが単一のSQLiteファイルでこの制限に達したケースってあったのかな?

KioxiaのLC9は最大245TBの容量で売られてるから、281TBを超える単一ディスクが登場するのも、あと1年くらいの話だね。

HPCシステムでより大きなファイルを見たことあるよ。確かに、これらは意図的に生成されたわけじゃないけど、でも実際にあったんだよね。

見た中で一番面白いのは、SQLiteのデータベースをHTTPサーバーに置いて、範囲リクエストを使って効果的に読み取れるってことだね。

つまり、HTTPサーバーをランダムアクセスできるデータストアとして使うってこと?それは正しい感じだね。

俺の経験では、データベースが読み取り専用のときにこれがうまくいく。そういう読み取り専用の場合は、Duckdb Wasmでクエリをかけたパーケットファイルを使うかな。

それに対する実装があるよ。例えば、https://github.com/psanford/sqlite3vfshttp や https://github.com/phiresky/sql.js-httpvfs みたいな。

そのリクエストのレイテンシは重要だよね。できるだけ大きなページサイズを使った方がいいし、keep aliveも活用した方がいいよ。でもそれでも、リクエストごとに最大64 KiBしか引き出せないんだ。もし応答時間が10msだったら、最大で52Mbpsしか出ない。だから、クエリが数ページだけを読むなら問題ないけど、全テーブルスキャンが必要なら、レイテンシを隠すために賢いプリフェッチングやキャッシングが必要だね。

たまに、もっと良いファイルフォーマット、例えばパーケットみたいな行指向のものができないかなって考えることがある。

Hacker Newsで議論の続きを見る