27 ポイント 投稿者 GN⁺ 2025-12-03 | 2件のコメント | WhatsAppで共有
  • SQLiteの単一ライター構造と組み込み型という特性が、むしろスケーラビリティと性能を高める要因として働くことを実験で実証
  • 同一条件で Postgresはネットワーク遅延時に348 TPSまで低下した一方、SQLiteはネットワークを排除することで 44,096 TPS を達成
  • 単一ライターモデルを活用した バッチ処理とSAVEPOINTベースの細粒度トランザクション により、最大 186,157 TPS、安定構成では 102,545 TPS を記録
  • アムダールの法則 がネットワーク型データベースのボトルネックを説明し、SQLiteはそれを回避することで高い効率を維持
  • この結果は ローカル環境におけるSQLite活用の可能性ネットワークボトルネック排除の重要性 を強調している

SQLiteの構造と実験環境

  • SQLiteは MVCCを持たず、単一ライターのみを許可 するが、この構造がむしろ高いスケーラビリティを可能にする
    • 組み込みデータベースであるため、ネットワークオーバーヘッドがない
  • ベンチマークは Apple M1 Pro、メモリ16GBのMacBook Pro(2021) 環境で実施
  • 実験は完全な最適化ではなく、一般的な条件でも高い書き込みスループットを達成できることを示す目的 で行われた

TPSの定義とトランザクション例

  • TPSは単純な書き込み速度ではなく、対話型トランザクション(Interactive Transaction) を意味する
    • 例:口座間送金では、複数のクエリとアプリケーションコードが1つのトランザクション内で実行される
  • トランザクションはエラー発生時に状態をロールバックできるため、一貫性維持において中核的な役割 を果たす

ベンチマーク構成

  • Clojureベースの仮想スレッド(virtual threads) を使って大規模な同時リクエストをシミュレーション
  • Postgresは HikariCPベースのコネクションプール で構成し、SQLiteは 単一ライターとコア数分の読み取り接続 を使用
  • 両データベースとも id, balance フィールドを持つ単純な account テーブルを使い、10億行 を挿入
  • ユーザー活動は べき乗則分布(0.9995) に従い、約 10万人のアクティブユーザー が存在

ネットワーク型データベース(Postgres)の性能

  • 同一サーバー内でPostgresは 13,756 TPS を達成
  • ネットワーク遅延を5ms追加すると 1,214 TPS、10msでは 702 TPS へ急減
  • シリアライズド分離レベルを適用後は 660 TPS、追加クエリを含めると 348 TPS まで低下
  • これは アムダールの法則 により、ネットワークボトルネックが全体性能を制限することを示している
    • ネットワーク遅延が増えると、トランザクションロック競合が激化してスケールしなくなる

SQLiteの組み込み型としての利点

  • ネットワークを排除した後、SQLiteは 44,096 TPS を達成
    • ネットワークボトルネックが消えることで、アムダールの法則の影響を最小化
  • 単一ライター構造を活用して バッチ処理(batch processing) を適用すると、186,157 TPS まで向上
    • 動的なバッチサイズ調整によって レイテンシ(latency)とスループット(throughput) を自動最適化

SAVEPOINTによる細粒度トランザクション

  • バッチ内の個別トランザクション失敗を防ぐため、SAVEPOINTを用いたネストされたトランザクション を適用
    • 失敗時はそのトランザクションだけをロールバックし、バッチ全体は維持
  • この方式でも 121,922 TPS を維持

読み取り/書き込み混在負荷テスト

  • 全リクエストの75%を読み取り、25%を書き込みで構成
  • 別個の読み取りスレッドプールを使い、読み取りリクエストが書き込みを妨げないよう分離
  • 結果として 102,545 TPS を達成

性能比較まとめ

条件 Postgres SQLite
ネットワークなし 13,756 44,096
5ms遅延 1,214 n/a
10ms遅延 702 n/a
10ms + シリアライズド 660 n/a
バッチ処理 n/a 186,157
バッチ + SAVEPOINT n/a 121,922
バッチ + SAVEPOINT + 読み取り n/a 102,545

結論

  • SQLiteは 単一ライターモデルと組み込み型構造 により、ネットワーク型データベースよりはるかに高いTPSを達成
  • アムダールの法則が示すネットワークボトルネックの限界 を回避することで、効率を最大化
  • 全コードはGitHubで公開されており、関連テーマとして アムダールの法則、べき乗則、SQLiteのスケーリング事例 などの資料もあわせて示されている
  • SQLiteは ローカル環境での高性能トランザクション処理 に非常に有効な選択肢である

2件のコメント

 
ppp123 2025-12-10

外部サーバーを介さずローカル環境だけで使うなら、ネットワークという税金を払う必要があるのか、ということですね。(VFS vs Socket)

 
GN⁺ 2025-12-03
Hacker Newsのコメント
  • 私は SQLite ベースのハイブリッド protobuf ORM/CRUD サーバーを作っています。
    コードと説明は GitHub - accretional/collector にあります。
    リアルタイムバックアップ時でも 5〜15ms のダウンタイム、数百件の読み書きリクエストのキューイング、CRUD 全体のレイテンシは 1ms 前後で、WAL ベースの ストリーミングバックアップ まで可能です。
    以前は Postgres と Spanner しか使っていませんでしたが、Collector にパーティション機能さえ追加されれば、もう Postgres は使わないと思います。

    • BTRFS のような atomic snapshot ファイルシステムを使って、SQLite + WAL で ゼロダウンタイムバックアップ を行う方法も検討したことがあるのか気になります。スナップショット後にゆっくりバックアップして削除すれば済みます。
  • 欠点は、すべてのデータと処理を 単一マシン に収める必要がある点です。
    AWS の u-24tb1.112xlarge インスタンス(448 vcore、24TB RAM、64TB EBS)を使えば、かなり余裕があります。

    • ただし Hetzner のベアメタルサーバー を借りれば、コアあたりの性能は 2〜3 倍で、コストは 90% 削減できます。
    • SQLite の 理論上の最大 DB サイズ は 281TB だと 公式ドキュメント に明記されています。実際にはファイルシステムの制限のほうが小さいですが、動作自体は問題ありません。
    • 単一マシンのスケールアップは安定していますが、弾力性(elasticity) に欠けます。トラフィック急増時には過剰に割り当てるか、障害を受け入れる必要があります。
    • 「データは RAM に収まるか?」を問う yourdatafitsinram.net のリンクを見ると、高性能な単一ノードなら EC2 より専用サーバーのほうが良いと思います。
  • この記事は SQLite の効率性を強調していますが、比較基準が不明確 だと感じました。
    もともと分離されたサーバー構成を前提にしていたのに、ローカルな組み込み DB の性能を測定していたからです。
    同じ条件なら、ローカル Postgres をチューニングしても似たような性能は出せます。

    • SQLite は同じマシン上の Postgres よりも速いです。実際のデプロイ環境の構成を基準にテストするのが妥当です。
    • SQLite を リクエストハンドラの後ろにラップして、別サーバーで動かすこともできます。結局 DB は、リクエスト処理系とストレージの組み合わせにすぎません。
    • 単一ボックスでは 生のスループット(raw throughput) が重要です。SQLite は PG より 10 倍速く、PG はトランザクションが複雑になるほど遅くなります。
    • 「それなら SQLite は比較対象ではない」というのは単純化しすぎです。そうすると記事が短くなりすぎます。
    • SQLite はモバイルや組み込み用途だけでなく、低並行性のサーバーアプリ にも適しています。Web サーバー専用の DB ではありません。
  • Postgres の接続数を 8 に制限したのは ボトルネック かもしれません。
    CPU とスレッド使用量もあわせて公開し、より大きいコネクションプールで再テストするとよいでしょう。

    • コネクションプールをコア数(8)に合わせたのは妥当ですが、トランザクション内に sleep があるならボトルネックになります。
      64 接続まで増やせばスループットが 8 倍になるかもしれません。限界に達するまで クライアント設定を拡張 すべきです。
    • この記事の数値は信じがたいです。私はネットワーク越しの MySQL でも、はるかに高い TPS を出しています。
  • 要点は、ネットワーク遅延がボトルネックかどうかを認識すること です。
    多くのワークロードでは、平凡なローカル DB のほうが優れたリモート DB より速いです。
    重要なのは「どの DB が最高か」ではなく、「ネットワーク境界をまたぐ必要があるのか」です。

    • (筆者)その通りです。SQLite vs Postgres の議論ではなく、ネットワーク型 DB の限界 を扱いたかったのです。
    • もちろん、すべてをメモリ上に置いて Redis や Memcache を使えば性能は簡単に上がります。しかしそれはルールが変わるということです。
  • ネットワーク型 DB には、アプリの再デプロイが容易という利点があります。
    新しいインスタンスを立ち上げて既存のものを停止すれば、ほぼ 無停止デプロイ が可能です。
    SQLite を同じインスタンスに置くと、置き換え時に DB も再起動しなければならず、より複雑になります。実運用でこうした問題を経験したことがあるのか気になります。

    • SQLite を本番で使うには 永続ストレージと NVMe が必要です。通常はベアメタルの単一サーバーで運用します。
      移行時にはダウンタイムが発生する可能性があります。Litestream のおかげで、今ではレプリケーションとバックアップが簡単になりました。
    • SQLite は マルチプロセスアクセス をサポートしているので、新しいプロセスを立ち上げて既存のものを停止する形の無停止切り替えも可能です。
  • 筆者は PRAGMA synchronous="normal" に設定していましたが、これは 毎回 fsync を実行しない ということです。
    公平な比較のためには "full" に設定すべきです。

    • ただし WAL モードでは "normal" でも問題ありません。電源断時には耐久性は失われますが、トランザクションの整合性 は保たれます。
  • SQLite の HA(高可用性) 構成はどうなるのか気になります。
    少なくとも自動フェイルオーバーが可能な程度にはなっていてほしいです。

    • SQLite は C ライブラリなので、rqlitelitestreamlitefs のようなプロジェクトで拡張できます。
      私はいま Postgres と SQLite(litestream 含む)のどちらにするか悩んでいます。
      私のアプリは多少のダウンタイムを許容できるので、単一ボックスで垂直スケールするほうがシンプルで安価です。
    • 最近では Marmot というマルチマスタープロジェクトが 2 年ぶりに復活しました。
      Marmot GitHubgossip ベースのレプリケーション機構 が新たに追加されました。
  • 実際に SQLite を 本番で限界まで使い込んだ事例 があるのか気になります。

  • 一般的な Web アプリやコマース環境で、SQLite vs Postgres の ユーザー数の限界 がどの程度なのか気になります。
    SQLite は最近のアップデートで 同時読み取り は可能ですが、単一書き込み しか許可されません。
    これがどのような場合に問題になるのか、そして将来的なスケールを考えるなら Postgres から始めたほうがよいのか、意見を聞きたいです。