SQLite3 の勉強を放置しているうちにSQLite4が出ていた。 なので今回はThe Design Of SQLite4の超訳(すっとばし)と補足を書く。

SQLite3 を読んでSQLiteは標準のB-Treeを基盤に仮想テーブルを使って色々なデータ構造をSQLで糊付けする抽象化層ライブラリってイメージを持っていた。 SQLite4 は各コンポーネントの責任範囲を明確にして全体を単純に扱えるようにしている印象を受けた。

例えば、プラガブルなストレージエンジンの採用は、データモデル(トランザクション・データ構造)を処理全体で一貫するように強制させている。 これは元々あったテーブル単位でのデータ構造切り替え(仮想テーブル)よりトランザクションのサポートなどが単純化され扱いやすくなると思えた。

また実行環境オブジェクトは複数のDB接続をユーザー側で明示的に管理しないといけなくしている。

参考資料のリンクを残す

2.0 概要 の大枠

  1. ACIDを完全にサポートしたSQLベースの組み込みDBでI/Oはディスクに直接向かう
  2. ライセンスは今まで通りパブリックドメイン
  3. 動的型付けを使っている
  4. デフォルトは1ファイルでフォーマットは安定しておりドキュメンテーションされてる
  5. 高速で信頼性があり管理者が不要
  6. 依存が少なく組み込みや一般的でない実行環境にも移植しやすい

ここだけ見るとSQLite3 との違いは少なそう。

3.0 主要な変更点 の概要

3.1 実行環境オブジェクト

いくつかのSQLite4 のAPIで実行環境を定義したsqlite4_envへのポインタが第一引数に追加された。

  • sqlite4_open()
  • sqlite4_malloc(),sqlite4_realloc(),sqlite4_free()
  • sqlite4_mprintf()
  • sqlite4_random()
  • sqlite4_config()

sqlite4_envは実行環境を表していてシステムの他の部分とのコミュニケーションを保持する。 メソッドは色々あるので原文を読んで欲しい。 上記で紹介した関数でsqlite4_envNULLポインタを渡すとグローバルなデフォルトのsqlite4_envオブジェクトが使用される。 異なるsqlite4_envを使えばmutex, heapなどが共用されないため同一プロセスで複数のsqlite4の利用が可能。

3.2 単純化されたKey/Value ストレージエンジン

SQLite4 はKey/Valueストレージエンジンを利用するようになった。 これはSQLite3 に比べてインタフェースが単純化されており更にプラガブルになっている。 新たなDBコネクションを開始する前にsqlite4_envを変更する事で動的に変更できる。

Key/Valueをテーブルを横断してグローバルに存在して辞書順ソートされている。 ストレージエンジンは切り替えれてデフォルトのストレージエンジンはlog-structured merge データベースでありLevelDBより早い。 B-Treeストレージエンジンも今後も提供される予定。

後日(db tech showcase Tokyo 2017)、テーブル更新で制約があったりするとreadが発生してLSM_Treeだと性能が出なく、やっぱり SQLite3 の方が全体的に良さそうと本人が言ってたらしい

3.3 プライマリキーが本当にプライマリキーになった

SQLite3 まではプライマリキーも内部的にはユニーク制約のインデックスのため 実際にレコードにアクセスするためと検索するためとで最低2回のI/Oが発生していたけれど今回からは違う。 そしてプライマリキーは_non null_が要求される。

これ普通なんだけどSQLite3 の初期バージョンで強制していなくて幅広いユースケースを見るとNOT-NULL制約を有効化するとトラブルが生じるプログラムが多く存在する。

3.4 10進数

SQLite4 では10進数を使う。整数型も浮動小数点型も内部に翻訳されて利用される。 内部では1から12バイトのバイト列で表現される。

IEEE754のバイナリ64浮動小数点がサポートされない環境でも動く だいたいの状況で正確で丸め誤差がない。 すべての符号(あり/なし)64bit整数型は正確に表現出来る。 浮動小数点の範囲や正確さはIEEE754のバイナリ64浮動小数点のそれらを超える。 正負の無限大とNaN(Not-a-Number)がwell-defined になる表現を取っている。

3.5 外部キー制約と再帰的なトリガーがデフォルトに

SQLite3 では、初期バージョンで外部キー制約は使用できなかったため、 後方互換性のためデフォルトでは有効になっていませんでした。 しかしSQLite4 ではデフォルトで有効です。 外部キー制約はデフォルトでは遅延制約になっています。 しかし定義時に即時制約(Immediate)にする事も可能になっている。 ただし外部キー制約の遅延と即時を切り替える仕組みは備えていない。 SQLite4 では再帰的なトリガーがデフォルトでサポートされている。

3.6 明示的なCovering Index

Coveringインデックスがサポートされている。 そのためインデックスに読むだけの情報を指定する事が可能となっている。 これによりインデックスで検索後にプライマリキーを用いてレコードを読み出しという探索が2回発生する状況を、インデックスで検索時に同時に情報を読み出しという探索が1回の形に変更できる。

これはSQLite4 ではアプリケーションエンジニアに容量と時間の対立を明確に選択できるようにしている事を表している。