低価格VPSにおけるSQLiteのパフォーマンス:実世界のワークロード・ベンチマーク
SQLiteからPostgreSQLのようなクライアント・サーバー型データベースへの移行時期に関する議論は、多くの場合「スケール」に焦点を当てます。しかし、スケールはしばしば、パフォーマンスのトレードオフのスペクトラム(連続体)としてではなく、二元的な閾値として誤解されがちです。SQLiteが実際にどこで限界に達するのかを理解するには、合成マイクロベンチマークを超えて、ワーキングセットが利用可能なシステムメモリを超えたときにどのように動作するかを調査する必要があります。
s13kによってHetznerの格安VPS($4.99/mo)で行われた最近のベンチマークは、SQLiteの能力を実用的な視点から示しています。3.7 GBのRAMしか搭載していないマシンで6 GBのデータベースをテストすることで、データ量の増加が最終的にハードウェアのリソースを上回るという実世界のシナリオをシミュレートし、エンジンにディスクへのアクセスを強制させています。
テスト環境
結果を本番環境に適用可能にするため、ベンチマークは以下の仕様を持つ低スペックで共有リソースのマシンで実行されました。
- Hardware: 2 vCPU Intel Xeon Skylake @ 2.1 GHz, 3.7 GiB RAM (no swap).
- OS: Debian 13 with an ext4 filesystem (
noatime,scheduler=none). - Software: SQLite 3.53.1, statically linked into a C benchmark tool.
本番環境に近い設定
最大限の速度を追求するのではなく、ベンチマークでは「本番環境で現実的な」pragmasが使用されました。この設定は、パフォーマンスとデータの安全性とのバランスを取っています。
journal_mode = WAL: Write-Ahead Loggingは、読み取りが書き込みをブロックすることなく、またその逆も同様に動作することを可能にし、より高い並行性を実現します。synchronous = NORMAL: これは重要なトレードオフです。NORMALは厳密なACID耐久性を持ちませんが(停電時にはWAL内の最新のトランザクションが失われる可能性があります)、データベースの破損を防ぎ、FULLよりも大幅に高速です。絶対的な耐久性が必要なアプリケーション(例:決済処理)では、FULLが不可欠な選択肢となります。page_size = 8192およびcache_size = 256 MiB。mmap_size = 256 MiB。
パフォーマンス分析:ディスク・バウンド vs. キャッシュ・バウンド
この研究の核心は、「キャッシュ・バウンド」状態(データベースがRAMに完全に収まる状態)と「ディスク・バウンド」状態(データベースがRAMより大きい状態)の比較にあります。
データベースがRAMを超える場合
6 GBのデータベースを使用する場合、すべてのランダム・リードはI/Oのペナルティを伴います。混合OLTPワークロード(読み取り70%、更新25%、挿入5%)の結果、スループットは3,915 ops/s、p99レイテンシは710 µs、p999は2.2 msとなりました。
| Phase | Throughput | p50 | p95 | p99 | p999 |
|---|---|---|---|---|---|
| BULK INSERT (10M rows) | 61,300/s | 8 µs | 58 µs | 80 µs | 143 µs |
| SELECT random PK | 3,609/s | 265 µs | 476 µs | 715 µs | 2.3 ms |
| SELECT indexed range scan | 3,477/s | 290 µs | 599 µs | 895 µs | 2.9 ms |
| UPDATE per-row | 2,986/s | 473 µs | 473 µs | 706 µs | 2.2 ms |
| MIXED OLTP | 3,915/s | 257 µs | 455 µs | 710 µs | 2.2 ms |
「エンジンの限界値」
ワーキングセットを約246 MB(100万行)に削減すると、データベースはシステム・キャッシュに余裕を持って収まりました。これにより、ディスクI/Oがホットパスから除外され、この特定のハードウェアにおけるSQLiteエンジンの最大潜在能力が明らかになりました。
- Random PK SELECTs: 3.6k/sから155.8k/sへ急増。
- Mixed OLTP: 3.9k/sから53.2k/sへ増加。
- Concurrent Reads: 10.3k/sから104k/sへ増加。
主要な教訓と「I/Oの崩壊」
2つの状態を比較すると、厳しい現実が浮き彫りになります。ワーキングセットがキャッシュを超えると、ランダム・リードは43倍の速度低下(崩壊)を起こします。これは、SQLiteアプリケーションがスケールする際の主なボトルネックは、エンジン自体ではなく、基盤となるストレージ・メディアであるということを示しています。
しかし、最悪のケースであるディスク・バウンドのシナリオでも、パフォーマンスは驚異的です。約3.9k ops/sのスループットは、$5のVPS上で毎時約1,400万件の操作に相当します。テール・レイテンシが3 ms未満に抑えられていることから、SQLiteは大多数のWebアプリケーションにとって、依然として非常に有力な選択肢です。
結論
ほとんどの開発者にとって、SQLiteの「スケール」の限界は、一般的に想定されているよりもずっと先にあります。RAMからディスクへ移行する際のパフォーマンスの低下は顕著ですが、絶対的なパフォーマンスの底辺は、最も安価なハードウェア上で本番環境の負荷を処理するのに十分なレベルにあります。すべての書き込みに対して厳密なACID耐久性を必要とするか、あるいは大規模な書き込み並行性が必要でない限り、SQLiteは多くの場合、十分すぎるほどです。