見落としているかもしれないモダンな SQLite の機能
SQLite を、モバイルアプリやちょっとしたプロトタイプにしか向かない軽量データベース、と未だに考えているのであれば、ここ数年の意義ある進化を見逃しています。SQLite は活発にメンテナンスされており、多くのワークロードにおいてより重量級のデータベースに匹敵する機能を備え、今ではブラウザ上で直接動作するようにもなりました。知っておく価値のあるポイントを紹介します。
主なポイント
- JSONB ストレージは、テキスト JSON よりも高速にパースできるコンパクトなバイナリ形式を提供し、JSON 式に直接インデックスを張ることができます。
- STRICT テーブルは SQLite に本物の型強制をもたらし、PostgreSQL のようなデータベースとの長年のギャップを埋めます。
- RETURNING 句により、INSERT、UPDATE、DELETE の後に SELECT を続ける必要がなくなります。
- 公式の SQLite WASM ビルドと OPFS による永続化により、ブラウザ常駐のデータベースが実用的なアーキテクチャ選択肢となります。
- WAL モードは、たった一つの PRAGMA 文で読み書きの同時実行性を改善します。
JSON と JSONB のサポート: 単なるテキスト保存以上のもの
SQLite は何年も前から JSON 関数を備えていますが、比較的最近追加されたのが JSONB サポートです。これはドキュメントをよりコンパクトに保存し、プレーンテキスト JSON よりも高速にパースできるバイナリ形式です。
jsonb() を使ってデータを保存すると、SQLite は読み取りのたびにテキストを再パースする必要がなくなります。大きな JSON ペイロードを扱う読み取り中心のワークロードでは、これが大きな違いを生みます。
CREATE TABLE events (
id INTEGER PRIMARY KEY,
payload BLOB NOT NULL -- store as JSONB
);
-- Insert using jsonb()
INSERT INTO events (payload)
VALUES (jsonb('{"user": {"id": 42}, "action": "login"}'));
-- Query with standard json_extract — works on JSONB columns too
SELECT json_extract(payload, '$.user.id') AS user_id
FROM events
WHERE json_extract(payload, '$.action') = 'login';
SQLite の JSON 関数はテキスト JSON と JSONB の値を透過的に受け付けるため、保存形式に関係なく json_extract() などの関数を引き続き利用できます。
JSON 式に直接インデックスを張ることもできるため、スキーマを非正規化することなくネストされたフィールドでの高速な絞り込みが可能になります。
CREATE INDEX idx_action ON events (json_extract(payload, '$.action'));
JSONB と TEXT の使い分け: SQLite が頻繁に JSON 値を処理またはクエリする場合は
BLOB+jsonb()を使用してください。挿入時の生の文字列をそのまま保持する必要がある場合はTEXTを使用してください。
⚠️ バージョンに関する注意: JSONB サポートは SQLite 3.45(2024 年 1 月)で導入されました。利用する前にランタイムのバージョンを確認してください。
SQLite STRICT テーブル: 本物の型強制
SQLite の柔軟な型付けは便利ですが、列が誤った型を黙って受け入れてしまうことで微妙なバグを生むことがあります。STRICT テーブルは、PostgreSQL の挙動と同様に、挿入時に列の型を強制することでこの問題を解決します。
CREATE TABLE users (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL,
age INTEGER NOT NULL
) STRICT;
age に 'twenty-five' を挿入しようとすると、SQLite は拒否します。STRICT テーブルでは、INT、INTEGER、REAL、TEXT、BLOB の 5 つの列型に加え、特別な ANY 型がサポートされます。ANY 型を指定すると、その列は SQLite の通常の柔軟な動作に戻るため、同じテーブル内で厳格な列と柔軟な列を混在させることができます。
⚠️ まずバージョンを確認: STRICT テーブルには SQLite 3.37 以降が必要です。
SELECT sqlite_version();で確認してください。
RETURNING 句: よりすっきりとした更新クエリ
行を挿入してすぐに生成された ID を取得するためにクエリを発行した経験があるなら、RETURNING でそのラウンドトリップを排除できます。
INSERT INTO orders (user_id, total)
VALUES (42, 99.99)
RETURNING id, created_at;
これは INSERT、UPDATE、DELETE で動作し、better-sqlite3 や Bun の組み込み SQLite のようなライブラリを用いたサーバーサイド JavaScript で特に有用です。RETURNING は SQLite 3.35 で追加されました。
Discover how at OpenReplay.com.
SQLite WASM: ブラウザで SQLite を直接実行する
SQLite プロジェクトは、ブラウザのタブ内で完全な SQLite エンジンを動作させる公式の WebAssembly ビルドを提供しています。先行する sql.js と異なり、公式の SQLite WASM ビルドは永続的でファイルベースのストレージのために Origin Private File System(OPFS) API をサポートしています。つまり、サーバーがなくてもページのリフレッシュをまたいでデータベースが保持されるということです。
これにより、SQLite フロントエンド開発として現実的なアーキテクチャが可能になります。
- ローカルでクエリし、後で同期するオフラインファーストのアプリ
- クライアントサイドの分析やレポーティングツール
- 環境を越えて単一のデータベース抽象化を求める Electron や Tauri のアプリ
- 本格的なクエリ機能を備えたブラウザベースの開発者ツール
OPFS はファイルシステム API の一部として MDN にドキュメント化されており、Google の web.dev ガイドによれば主要なすべてのブラウザでサポートされています。一部の OPFS バックエンドの SQLite WASM 構成では、選択する VFS 実装によっては、セキュアコンテキスト(HTTPS)、SharedArrayBuffer サポート、適切な COOP/COEP ヘッダーが必要となる場合もあります。
WAL モード: 設定の手間なしでより良い同時実行性
ライトアヘッドロギングを使うと、読み手と書き手が互いをブロックすることなく同時に作業できます。読み書きが同時に発生するアプリケーションや、体感レイテンシーが重要なアプリケーションでは、WAL モードを有効にする価値があることが多いです。
PRAGMA journal_mode = WAL;
この単一の pragma は、ローカルファーストのアプリ、Electron アプリ、SQLite が実トラフィックを処理する軽量バックエンドサービスのパフォーマンスを大きく改善することがあります。WAL モードはデータベースファイルがローカルディスクに存在することを必要とし、ネットワークファイルシステム上では確実には動作しない点に注意してください。
まとめ
JSONB、STRICT テーブル、RETURNING、OPFS を伴う WASM、WAL モードといったモダンな SQLite の機能を組み合わせれば、SQLite は世間のイメージよりもはるかに広い範囲のアプリケーションにとって信頼できる選択肢になります。プロジェクトは活発に開発されており、大規模なマルチライター同時実行を必要としないワークロードについては、SQLite と重量級データベースの差はかなり縮まりました。最近 SQLite で何ができるかを見直していないなら、今がそのよい機会です。
FAQ
多くのワークロードについては、はい。SQLite は読み取り中心のトラフィックや小〜中規模の書き込みボリュームをうまく処理でき、特に WAL モードを有効にした場合に有効です。シングルサーバーのデプロイメントやローカルファーストのアプリに最も適しています。分散サーバー間で複数の同時ライターを必要とするアプリケーションには、PostgreSQL のようなクライアント-サーバー型データベースの方が依然として適しています。
SQLite が JSON 値を頻繁に処理またはクエリする場合は JSONB を選びましょう。読み取りのたびに再パースが不要で、データもよりコンパクトに保存されます。空白やキーの順序を含めて元の文字列を書き込まれたとおりに正確に保持する必要がある場合(暗号署名や監査ログなどで重要)には TEXT を使い続けてください。
いいえ。STRICT はテーブルごとのオプトインであり、既存のテーブルは引き続き SQLite の柔軟な型付けを使用します。新しいスキーマで STRICT テーブルを導入したり、特定のテーブルを段階的に移行したりすることができます。CREATE TABLE 文に STRICT キーワードを追加する前に、SQLite 3.37 以降を実行していることだけは確認してください。
近いですが同一ではありません。WASM ビルドは WebAssembly のオーバーヘッドや、OPFS のファイルアクセスがネイティブのディスク I/O ほど直接的でないことから、ネイティブ SQLite よりも遅く動作します。多くの控えめなクライアントサイドのワークロードであれば差は許容範囲ですが、大規模なデータセットや重い分析クエリでは、依然として目に見える遅さが現れることがあります。
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.