【SQLite入門】WITHOUT ROWIDテーブルでパフォーマンスを向上させる

SQLiteでは、テーブルを作成するとROWID列が自動で生成されます。

このROWID列が無いテーブル(WITHOUT ROWID)を使用することで、パフォーマンスを向上できるケースがあり、以下ではその理由などについて記載しています。

1. パフォーマンスが上がる理由

次のような商品テーブルがあるとします。

このようなROWID列があるテーブルの場合、検索するB-treeが2つ作成されます。

1つめのB-Tree(ROWID検索)
ROWIDで検索するために使用されます。表のidやnameの実際の値は、ROWIDとペアでこのB-Treeに格納されます。

2つめのB-Tree(主キー検索)
主キー(id)で検索するために使用されます。主キーに紐つくROWID が格納されています。

仮に、主キー(id)で検索を行った場合、次の動作になります。

  1. 2つめのB-Treeを主キーで検索して、紐つくROWIDを取得
  2. 1つめのB-Treeを 1 で取得したROWIDで検索して、idやname列の実際の値を取得

このように、主キー列で検索をしますが、実際の値を持っているのは、ROWIDのB-Treeのため、2回 B-Tree を検索する必要があります。

また、データのインサート時にも2つのB-Treeをメンテするコストも必要になります。

そのため、WITHOUT ROWIDテーブル(ROWIDなしテーブル)では、ROWIDのB-Treeが不要になり、

  1. 主キーで検索すると 1回のB-Treeの検索で値を取得することができる
  2. B-Treeのメンテコストも低くなる

という理由から、パフォーマンスの向上が期待できます。

2. WITHOUT ROWIDテーブルの主な制約

WITHOUT ROWIDテーブルでは、ROWIDつきテーブルと異なり、主に以下の制約が適用されます。

  1. テーブルに主キー(PRIMARY KEY )が必要
  2. AutoIncrement が使用できない
  3. 主キーにNOT NULL制約がつく

1. テーブルに主キーが必要

ROWIDつきテーブルでは、ROWIDが一意な値のため、主キー制約は任意でした。

WITHOUT ROWIDテーブルでは、ROWIDが無いため明示的に行を一意に特定できる主キーを定義する必要があります。

2. AutoIncrement が使用できない

AutoIncrement機能は、ROWIDが存在することが前提で動作するため、WITHOUT ROWIDテーブルでは使用することができません。

AutoIncrementの詳細については、こちら(AutoIncrement の使用方法と注意すること)を参照してください。

3. 主キーにNOT NULL制約がつく

ROWIDつきのテーブルでは、過去の不具合との互換性のため、主キーにもNULLを登録することができました。

WITHOUT ROWIDテーブルでは、SQL標準の動作を行い、主キーにNULLを登録することはできません。

3. ROWIDつきテーブルを使用するケース

次の場合は、ROWIDつきテーブルの方が高速に動作する可能性があります。

  1. INTEGER PRIMARY KEY をもつテーブル
  2. テーブルの個々の行データが大きすぎない

1. INTEGER PRIMARY KEY をもつテーブル

INTEGER PRIMARY KEY 列は、ROWIDのエイリアスとして機能します。

そのため、INTEGER型の主キーをもつテーブルの場合は、ROWIDつきテーブルの方が早く動作する場合もあります。

なお、INTEGER PRIMARY KEY 列 を使用する際の注意事項は、こちら を参照してください。

2. テーブルの個々の行データが大きい

ページサイズを目安に、次に該当する場合は、ROWIDつきのテーブルの方が高速に動作する傾向があります。

ページサイズが1KiBの場合:50バイトを超える
ページサイズが4KiBの場合:200バイトを超える

4. WITHOUT ROWIDテーブルの作成方法

最後になりましたが、WITHOUT ROWIDテーブルは、通常のCREATE TABLE 文の末尾に、WITHOUT ROWID 句をつけることで作成することができます。

参考サイト

Clustered Indexes and the WITHOUT ROWID Optimization

スポンサーリンク

シェアする

  • このエントリーをはてなブックマークに追加

フォローする