FirefoxのSQLiteDBの再編成について(すこし詳細に)

物凄い人気ですね。
これについてちょっと詳しく書いてみようと思う。

DBファイルの断片化

WindowsファイルシステムデフラグしましょってやつはDBファイルにも言えることだ。
仕組みをLeo's Chronicle: データベースシステム入門:「データベースは体育会系図書館?」に習って「図書館」に例えてみる。

図書館
DBファイル
中身のデータ一行

といえるだろう。

単純にデータが追加されていくだけなら、本を本棚の末尾に追加するだけなのでデータは詰まったままだし楽チンだ*1
途中データの削除(本を抜き取る)を考えてみる。抜き取った後本を詰めないと空白ができる。
また、データ更新(本の交換)を考えてみる。同じ大きさなら良いが。大きかったり、小さかったりすると空白ができる。
こうしてデータ削除/更新を頻繁に行うと穴だらけの本棚になる。これが断片化だ。ファイルシステムのそれも同じ概念だろう。
毎回本を詰めれば良いじゃないかと思うかもしれないが、後続の本を一つずつ詰めるのは大変労力かかるので、この問題は後回しにするのが近作のRDBMSだ。
断片化が進むとどうなるかというと、本棚を一望した時に見つける本の量((SQLiteではページ・サイズといい、PRAGMA page_sizeで見ることが可能))が減る。本の冊数の割りに全部を見るのに時間がかかることになる。これがパフォーマンスの悪化要因の一つだ。

索引

どうしても書店のように本棚を縦横に綺麗に並べたくなってしまいますが、そこはさすが1970年代の研究者。発想が違います。彼らは本棚を縦横ではなく、ピラミッド状に並べることを考えました。

Leo's Chronicle: データベースシステム入門:「データベースは体育会系図書館?」

の様に、図書館で例えると索引の説明が難しくなってしまうのだが...。
索引もデータの増減により最初は綺麗だった「ピラミッド構造」がだんだん歪になっていき、使い難いものになる。
これを検索しやすい形に整形するのがREINDEXコマンドとなる。
議事録をマインドマップを手で書いて、あとでソフトを使って綺麗にする、みたいなものだ。


まえおき、終わり

Firefoxが使用するDBファイル

Firefoxでは主に以下のファイルがSQLiteDBだ。

ファイル名 データサイズ 更新度 概要
urlclassifier3.sqlite 悪意のあるサイトや偽装サイトのデータ
places.sqlite ブックマークや訪問履歴
formhistory.sqlite フォームの入力履歴
signons.sqlite パスワードの保存許可設定やパスワード自体
cookies.sqlite Cookieデータ
content-prefs.sqlite サイト毎の設定
downloads.sqlite ダウンロード履歴
permissions.sqlite Cookieや画像読み込みなどの許可設定
search.sqlite 検索エンジン

※データサイズ、更新度は個人的な感覚でつけているので個人差があると思う

urlclassifier3.sqlite

とにかくサイズが大きい(通常のRDBMSのDBファイルに比べたら小さいものだが)
さらに、このファイルはプロファイルフォルダに無く、別のフォルダに保管されている。

Windows
%USERPROFILE%\Local Setteings\Application Data\Mozilla\Firefox\Profies\ランダム文字列.プロファイル名\ 以下
Mac
~/Library/Caches/Firefox/Profiles/ランダム文字列.プロファイル名/ 以下(elimさん、ありがとうございます)
Linux
~/.mozilla/firefox/ランダム文字列.プロファイル名/ 以下(necydaさん、ありがとうございます)

VACUUM,REINDEXの第一候補である。これを再編成することで起動時のパフォーマンスはかなり上がるはず。

places.sqlite

ブックマーク、訪問履歴を扱っているので更新頻度が高く、履歴の保存日数設定によってはサイズも大きくなる。
再編成第二候補。
再編成することで、ロケーションバーでの補完のパフォーマンスが改善されると思われる。

その他

他はそんなに大きなサイズにはならないと思う。cookies.sqlite辺りはデフォルトでCookieを許可している場合はそれなり溜まるかもしれないが...(私はデフォルトでは許可していないので10KBに満たない)

断片化が進んでいるかの調査方法

sqlite3コマンドが使えるという前提で書く。
以下のコマンドで各値を得る。

ページサイズ(Byte)
PRAGMA page_size
全体ページ数
PRAGMA page_count
空きページ数
PRAGMA freelist_count

ページサイズ * 全体ページ数 ≒ ファイルサイズ である。また断片化が進んでいるほど、空きページ数が大きくなる。

urlclassifier3.sqliteを例にとると

ページサイズ
4096
全体ページ数
6080
空きページ数
567

約10%、2.2MBほどの空きがあることが分かる。
この空きページ数が再編成の一つの指標になると思う。どのくらい断片化すると体感速度に影響が出るのか分からないけど...。

最後に、Webサイトの読み速度などに変化はないはずなので何でも早くなるわけじゃないことに注意。

*1:本棚は自動拡張/縮小とする