SQLite で STRICT テーブルを優先する

SQLite で STRICT テーブルを優先する

データ整合性を強制するために STRICT テーブルを使用する

SQLite の STRICT テーブルは、宣言されたデータ型のみが列に格納できるように厳格な型付けを強制することで、一般的なデータ整合性の問題を防ぎます。CREATE TABLE 文の末尾に STRICT を付加するだけで、開発者は非 strict テーブルでデフォルトで許可されている整数列へのテキスト挿入やその他の型不一致を防ぐことができます。

-- 非 strict テーブルは任意の型を任意の列に許可する
CREATE TABLE people_nonstrict (age INTEGER);
INSERT INTO people_nonstrict (age) VALUES ('garbage'); -- 問題なく実行される

-- Strict テーブルは宣言された型を強制する
CREATE TABLE people_strict (age INTEGER) STRICT;
INSERT INTO people_strict (age) VALUES ('garbage'); -- エラー: TEXT 値を INTEGER 列に格納できません

ロスレス変換は依然として許可されています。たとえば文字列 '123' は整数に完全に変換できるため、INTEGER 列に格納できます。

無効な列定義の防止

Strict テーブルは、存在しない型や綴り間違いのデータ型で列を作成する可能性を排除します。標準的な SQLite テーブルでは、DATETIMEJSONUUID などの型が SQLite のネイティブ型でなくても受け入れられますが、STRICT テーブルでは以下の型だけが許可されます。

  • INT / INTEGER
  • REAL
  • TEXT
  • BLOB
  • ANY

テーブル作成時に他の型名を使用しようとするとエラーとなり、タイプミスや SQLite がサポートする型に対する誤解を防げます。

ANY 型による柔軟性

キー‑バリュー・ストアや、異なるフィールド型を追跡する監査テーブルなど、列を柔軟に保つ必要があるシナリオでは、strict テーブル内で ANY 型を使用できます。これにより、その列は任意のデータ型を受け入れつつ、テーブル全体は厳格に型付けされたままです。

CREATE TABLE tbl (value ANY) STRICT;
INSERT INTO tbl (value) VALUES (123);
INSERT INTO tbl (value) VALUES ('text');

STRICT テーブルのトレードオフと制限

STRICT テーブルは予測可能性を向上させますが、いくつかの技術的制約があります。

バージョン要件と互換性

Strict テーブルは SQLite バージョン 3.37.0(2021 年 11 月)で導入されました。3.37.0 未満の SQLite では strict テーブルを含むデータベースを読み取れないため、レガシー SQLite がインストールされた環境では互換性のハードルが生じます。

移行の課題

既存のテーブルは ALTER TABLE コマンドで strict に変換できません。非 strict テーブルを strict に移行するには、新しい strict テーブルを作成し、データをコピーする必要があります。

  1. 同じスキーマで新しい strict テーブルを作成する。
  2. INSERT INTO ... SELECT * FROM ... でデータをコピーする。
  3. 古いテーブルを削除し、新しいテーブルの名前を変更する。

既存データに型不一致がある場合、移行は失敗し、先にデータをクリーンアップまたはキャストする必要があります。

パフォーマンスへの影響

Strict テーブルは INSERTUPDATE 時にデータ型を検証するため、わずかなオーバーヘッドが発生します。しかし、実証テストではこのオーバーヘッドはほとんどの実用的なアプリケーションで無視できる程度であり、列のアフィニティ不一致を回避することでパフォーマンスが向上する可能性があると主張する声もあります。

柔軟な型付けと厳格な型付けに関するコミュニティの見解

SQLite の開発者と多くのユーザーの間で、柔軟な型付けの有用性について大きな意見の分かれがあります。公式ドキュメントは柔軟な型付けを利点とし、汚れたデータ(CSV など)のインポート時にデータ損失を防ぎ、特定のバグを見つけやすくすると主張しています。

コミュニティメンバーの意見は様々です:

"予期しないデータ型が原因で微妙なバグが多数発生した経験があります。こうしたミスは大きくエラーとして表面化してほしいです。"

"あるアプリが文字列を数値列に格納すると、他のすべてのユーザーが壊れます… SQLite の主な利用ケースは組み込みデータベースです。アプリ側のコードが各列で何を期待しているかを知っているべきです。"

一方で、strict モードはアプリケーション層でのマッピングに使える、より意味のある列型名(例: Rust の sqlx クレート)を使用できなくなると主張するユーザーもいます。

バージョン制約や特定の制約が必要で STRICT テーブルを使用できない場合は、CHECK 制約を手動で利用してデータの正確性を強制することが代替手段となります。


要約

SQLite の STRICT テーブルはバージョン 3.37.0 で導入され、型の不一致や無効な列定義を防ぐために厳格な型付けを強制し、SQLite のデフォルトである柔軟な型付けに対するより予測可能な代替手段を提供します。

Sources