- SQLiteは、小さなBlob(例: サムネイル画像)を個別ファイルで
fread() や fwrite() を使って読み書きするよりも、35%高速に読み書きできる
- また、10KBのBlobを保存する単一のSQLiteデータベースは、Blobを個別ファイルとして保存する場合よりも、ディスク容量を約20%少なく使用する
- この性能差は、SQLiteデータベースで作業する場合は
open() と close() のシステムコールが1回だけ呼ばれる一方、個別ファイルのBlobを使う場合はBlobごとに open() と close() が1回ずつ呼ばれるために生じるとみられる。open() と close() のオーバーヘッドは、データベース利用のオーバーヘッドより大きいようだ
- 容量削減は、個別ファイルがファイルシステムのブロックサイズの次の倍数まで埋められる一方で、BlobはSQLiteデータベース内により高密度に格納されるために生じる
注意事項
- 35%という数値はおおよその目安。実際の計測値はハードウェア、オペレーティングシステム、実験の詳細によって異なり、実機ではランダムな性能変動もある
- 35%という数値は、著者が容易に利用できたすべてのシステムでテストを実行した結果。一部のレビューアーは、自分たちのシステムではSQLiteの方が直接I/Oより高いレイテンシを示したと報告している。その差の理由はまだ理解されていない
- SQLiteは、コールドなファイルシステムキャッシュを使って実験を行う場合、直接I/Oほど良い性能は出ないことが分かっている
- この文書は、リレーショナルデータベースは直接のファイルシステムI/Oより遅いはずだという一般的な想定に反論している
- 2022年の研究によれば、実際のワークロードではSQLiteはLinuxのBtrfsおよびExt4と比べておおむね2倍高速だった
測定方法
- I/O性能は、SQLiteソースツリー内の
kvtest.c プログラムを使って測定された
- このテストプログラムをコンパイルするには、SQLiteのアマルガメーションソースファイル
sqlite3.c と sqlite3.h に加えて、kvtest.c ソースファイルを1つのディレクトリに集め、Unixで次のようなコマンドを実行する
- このコマンドで生成される
kvtest プログラムを使って、100,000個のランダムな非圧縮Blobからなるテストデータベースを作成する。各Blobのサイズは8,000バイトから12,000バイトの間
- すべてのBlobのコピーをディレクトリ内の個別ファイルとして作るには、
--tree コマンドラインオプションを使って export コマンドを実行できる
- データベースからBlobを読み取る性能と、個別ファイルからBlobを読み取る性能を測定するために、次のコマンドを使う
--blob-api オプションを使うと、SQLiteはSQL文を実行する代わりに sqlite3_blob_read() 関数を使ってBlob内容を読み込めるため、読み取りテストではわずかに高速になる
読み取り性能の測定
- Windows 10では、SQLiteデータベースからのコンテンツ読み取りは、ディスクから直接読み取る場合より約5倍高速
- Androidでは、SQLiteはディスク読み取りより約35%高速
- メモリマップされたデータベースで
sqlite3_blob_read() を使って読み取る場合、MacとAndroidではディスク上の個別ファイル読み取りより2倍高速で、Windowsでは10倍高速
書き込み性能の測定
- すべてのシステムで、直接I/OとSQLiteのどちらも書き込み性能は読み取りより5〜15倍遅い
- 書き込みテストでは、アンチウイルスソフトウェアはSQLiteへの書き込みにはほとんど影響しないが、ディスクへの直接書き込みは約10倍遅くなる
- これはおそらく、SQLiteは単一のデータベースファイルだけを変更する一方、ディスクへ直接変更する場合はアンチウイルスが検査すべき何千もの個別ファイルを変更するため
一般的な結果
- SQLiteは、読み取り・書き込みの両方において、別個のディスクファイルに保存されたBlobと十分競争力があり、多くの場合より高速
- SQLiteは、アンチウイルス保護が有効なWindowsでは、ディスクへの直接書き込みよりはるかに高速
- 読み取りは、すべてのシステムにおいて、またSQLiteと直接ディスクI/Oのどちらでも、書き込みより約10倍高速
- I/O性能はオペレーティングシステムとハードウェアによって大きく異なる。結論を出す前に自前で測定する必要がある
- 一部の他のSQLデータベースエンジンは、開発者にBlobを別ファイルとして保存し、そのファイル名をデータベースに保存するよう勧めている。この場合、Blob全体をデータベースに保存した方が、SQLiteでははるかに高速な読み書き性能を得られる
GN⁺の見解
- SQLiteの性能が個別ファイルの読み書きを上回るという点は非常に興味深い。これは、データベースを使うアプリケーションの性能向上に役立つ可能性がある
- ただし、このベンチマーク結果がすべての状況に一般化できるわけではない。データの特性、アクセスパターン、ハードウェア構成などによって変わり得る。重要なアプリケーションでは、実際のワークロードを使ってベンチマークを行うことが重要
- また、SQLiteにはアンチウイルス検査の影響を受けにくいという利点がある。これは大量の小さなファイルを扱うアプリケーションで特に有用だろう
- SQLiteの欠点は、すべてのデータが単一ファイルに保存されるため、データベースファイルが破損するとすべてのデータを失う可能性がある点。そのため、データベースファイルを定期的にバックアップすることが重要
4件のコメント
データベースにファイル属性(ファイル名、サイズ、アクセス権限、…)へのアクセスまで含めるのか、
そうでないなら、ファイルI/OではなくブロックI/Oと比較すべきなのでは、という気がします…。
何はともあれ、SQLite が速いのは確かですね。
Hacker Newsの意見
ファイルシステムの属性やメタデータがないため、追加の属性記録や更新が不要で、実ファイルやパイプ/シンボリックリンクの確認、権限チェック、ブロックサイズのアラインメント不一致などもなく、単一の open コマンドだけで済む
rsyncのようなシェルコマンドでファイルを探索・操作できる単純さがあるWindows 10 で 4 倍の高速化が見られるのは、Windows のファイルシステム呼び出しがどれほど遅いかを強調している
デジタルピアノから出るすべてのノートをリアルタイムで記録するアイデアがある
データベース研究室で、OS 研究と比較するのが興味深かった
WAL2 モードで sqlite DB に追記することを検討している
SQLite データベースでは
open()とclose()のシステムコールが 1 回ずつしか呼ばれないSQLite の blob フィールドを使ってファイルを保存するのは推奨されない
ファイルシステム上に構築されたものがファイルシステムより速いというのは、最適化されていない方法でファイルシステムを使うと遅いことを意味する
SQLite データベースで大量の行を削除するのは、ファイルを削除するより遅い
すべてのファイルシステム/ドライブアクセスは OS によって管理される
20年前、ファイルをblobとしてOracle DBに入れるアーキテクチャをうまく使っていたが、その利点を毎回人々に説明しなければならなかった。もちろん、毎回うまくいったわけではなかった。
20年前なら、オラクルのSAN DISKの価格もかなり高かったでしょうね..