コンテンツにスキップ

pgmem

テストのための、メモリ上で動く本物の PostgreSQL 18。Docker もディスクも使いません。スキーマを一度だけ準備し、読み取りテストで共有し、書き込みテストにはミリ秒で専用の複製を渡します。

同じスキーマ、同じクエリ、同じテスト単位の分離を、同じマシンで計測しました。比較相手は公式イメージを使った docker run、Testcontainers、devbox で入れた PostgreSQL です。

5 回計測した中央値です。Docker と Testcontainers のメモリは OrbStack を再起動して 3 回測定しました。バーは各カード内の最大値を基準にし、短いほど値が小さくなります。

起動から最初のクエリまで

起動コマンドから TCP SELECT 1 まで。取得時間は除外し、Devbox は初期化済みクラスタを使います。

  • pgmem · Go ライブラリ70 ms
  • Docker · PostgreSQL 181.65 s
  • Testcontainers · Go1.09 s
  • devbox · services up411 ms

テストごとの複製

DB を分離し、結合クエリを実行する時間の中央値。

  • pgmem · Go ライブラリ14 ms
  • Docker · PostgreSQL 1861 ms
  • Testcontainers · Go21 ms
  • devbox · services up83 ms

インデックス SELECT

ウォームアップ後に行う TCP 経由の検索。

  • pgmem · Go ライブラリ34 µs
  • Docker · PostgreSQL 1893 µs
  • Testcontainers · Go102 µs
  • devbox · services up28 µs

20万行ソート

20 万行を並べ替えて数える時間の中央値。

  • pgmem · Go ライブラリ120 ms
  • Docker · PostgreSQL 18259 ms
  • Testcontainers · Go258 ms
  • devbox · services up228 ms

DB と計測プロセスのメモリ

スキーマ準備後、クエリ前の値です。Docker と Testcontainers はコンテナ使用量(Testcontainers は PostgreSQL と Ryuk)と計測プロセスの増分を合算します。OrbStack VM の変化は別に示します。

  • pgmem · Go ライブラリ110 MiB
  • Docker · PostgreSQL 1877 MiB
  • Testcontainers · Go137 MiB
  • devbox · services up36 MiB

初回取得サイズ

同じ MB スケールですが、Go のリンク増分、圧縮イメージ、devbox の取得量で測る対象が異なります。

  • pgmem · Go ライブラリ37.9 MB
  • Docker · PostgreSQL 18117.9 MB
  • Testcontainers · Go120.0 MB
  • devbox · services up112.7 MB

クエリ性能、計測方法、再現手順はベンチマークのページにあります。

本物の PostgreSQL

PostgreSQL 18.3 を WebAssembly にコンパイルし、Go に変換したものです。SQL の解釈もプランナの挙動もエラーコードも、エミュレータではなく PostgreSQL そのものです。

インストールするものがない

各言語で依存はひとつ。Docker デーモンも、CI 上のコンテナランタイムも要りません。ディスクにも書き込みません。

読み取りは共有、書き込みは分離

マイグレーションとシードは一度だけ。読み取り専用テストではフォークを共有し、書き込みテストには専用の複製を渡します。書き込みテスト同士も並列に走らせられます。

ドライバを選ばない

PostgreSQL のワイヤプロトコルで待ち受けるので、pgx、psycopg、JDBC、node-postgres、ORM、マイグレーションツールがそのまま動きます。

s, err := pgmem.Start(ctx, pgmem.Options{Database: "app"})
if err != nil {
t.Fatal(err)
}
defer s.Close()
db, _ := sql.Open("pgx", s.DSN())