Realmのディスク消費量について調べてみた

#はじめに
Realmを始めて5日目。だんだん面白くなってきました。
私は組込み系からやってきた人間なので、レコードにフラグ的な情報が多い場合はサイズ節約のためint型にビットパターンで持たせたくなります。

MySQLなどのRDBはほとんどビット演算の機能を持っていますが、RealmではそれらしいAPIが見当たりません。
しかたなくビット演算はあきらめてbooleanの配列で実装することにしました。
最初はRealmList\<boolean\>のデータメンバをRealmObjectに追加してみたのですが、プリミティブ型のRealmListは**まだサポートされてない**ということでNGでした。
booleanのメンバを1個だけ持つRealmObjectクラスを作成し、それをRealmListに入れる必要があるようです。
そうなるとレコードサイズが大きくなりそうなので、Realがどれだけディスクサイズを消費するのか調べてみました。


#実験
Realmはバージョン0.88.2。Java環境です。
まずはレコード数ゼロの初期状態

```text
-rw------- u0_a58   u0_a58       8192 2016-04-11 06:57 empty.db
```

8KB消費されるようですね。


次にbooleanメンバが1個のクラスと32個のクラスで評価してみました。
それぞれファイルがbool1.db、bool32.dbに対応しています。

```java
// for boot1.db
public class TestBool1 extends RealmObject {
	private boolean value;
}

// for boot32.db
public class TestBool32 extends RealmObject  {
	private RealmList<TestBool1> values;
}
```

以下、ログです。

```text
1レコード追加
root@generic_x86:/data/data/com.sakura_apps.realmtest/files # ls -l *.db
-rw------- u0_a58   u0_a58       8192 2016-04-11 07:05 bool1.db
-rw------- u0_a58   u0_a58      12288 2016-04-11 07:05 bool32.db


10レコード追加
-rw------- u0_a58   u0_a58       8192 2016-04-11 07:10 bool1.db
-rw------- u0_a58   u0_a58      12288 2016-04-11 07:10 bool32.db

1000レコード追加
-rw------- u0_a58   u0_a58      12288 2016-04-11 06:57 bool1.db
-rw------- u0_a58   u0_a58     163840 2016-04-11 06:57 bool32.db
```


bool1.dbでは1レコードと10レコードで差がないですね。
最初にある程度まとまったサイズを確保しておいて、足りなくなるとまた確保しているようです。
増分が4KBなのでセクタサイズなどを意識したサイズでしょうか？

1レコードあたりミニマムでどれだけ消費するのか調べてみました。
int型のメンバをひとつだけ持つRealmObjectを１レコードずつ追加していって、ファイルサイズに変化がでたところでログ出力してみました。

```text
I/MainActivity: size update at #0     size: 8192
I/MainActivity: size update at #1     size:12288
I/MainActivity: size update at #20    size:16384
I/MainActivity: size update at #16843 size:20480
I/MainActivity: size update at #36838 size:24576
I/MainActivity: size update at #55965 size:28672
I/MainActivity: size update at #76001 size:32768
```

増分はいずれも4KBです。この4KB増える間のレコード数にはバラツキがありますね。
インディクス生成用の領域がからんでいるんでしょうか。

と、ここで重大な事に気づきました。
\#76001の例だとデータサイズは4byte*20036=約80KB増えているはずなのにディスク増加量が4KBしかありません。
圧縮的な仕組みが備わっているのかな。。。
試験データは常に1をセットするようにしていましたが、これを現在時刻(msec)に変えて検証してみました。


```text
I/MainActivity: size update at #0    size: 8192
I/MainActivity: size update at #1    size:12288
I/MainActivity: size update at #18   size:16384
I/MainActivity: size update at #260  size:20480
I/MainActivity: size update at #520  size:24576
I/MainActivity: size update at #550  size:28672
I/MainActivity: size update at #1530 size:32768
I/MainActivity: size update at #2519 size:36864
I/MainActivity: size update at #3518 size:40960
I/MainActivity: size update at #4515 size:45056
```

前半はバラツキがありますが、後半は4KBあたり980-999個と安定しています。
データのint(4byte)とほぼ同じだけディスク容量が増えているようです。


次に各データ型で比較してみました。
この実験の意図はboolean型がrealm内部ではビットで保持されているのでは？という期待を検証するためです。
各データ型に前のテストと同じようにメンバ1個を持つクラスとRealmListに入れて32個持つクラスを用意しました。
データの初期化はbooleanは常にtrue, それ以外は現在時間(msec)をセットしました。

```text
100000レコード追加
-rw------- u0_a58   u0_a58      12288 2016-04-11 09:26 bool1.db
-rw------- u0_a58   u0_a58    2097152 2016-04-11 09:26 bool32.db
-rw------- u0_a58   u0_a58      20480 2016-04-11 09:26 byte1.db
-rw------- u0_a58   u0_a58    2359296 2016-04-11 09:27 byte32.db
-rw------- u0_a58   u0_a58      53248 2016-04-11 09:27 int1.db
-rw------- u0_a58   u0_a58    3407872 2016-04-11 09:27 int32.db
-rw------- u0_a58   u0_a58     147456 2016-04-11 09:27 long1.db
-rw------- u0_a58   u0_a58    4718592 2016-04-11 09:29 long32.db
```

boolean型もbyte型もさほど変わらないです。boolean型はデータが同じで圧縮が効いてそうなので、データがばらければサイズが膨らみそうです。
int型くらいのサイズで確保されているのかもしれません。


#まとめ
- Realmファイルは4KBずつ拡張されていく
- Realmには圧縮的な仕組みが有る？
- ある程度はデータ増分とディスク使用量増加は一致
（インディクスとか他のオブジェクトとの関連がある場合は多分、もっと複雑）
- boolean型はそんなに小さくない(int型相当？）