本物の PostgreSQL
PostgreSQL 18.3 を WebAssembly にコンパイルし、Go に変換したものです。SQL の解釈もプランナの挙動もエラーコードも、エミュレータではなく PostgreSQL そのものです。
同じスキーマ、同じクエリ、同じテスト単位の分離を、同じマシンで計測しました。比較相手は公式イメージを使った docker run、Testcontainers、devbox で入れた PostgreSQL です。
5 回計測した中央値です。Docker と Testcontainers のメモリは OrbStack を再起動して 3 回測定しました。バーは各カード内の最大値を基準にし、短いほど値が小さくなります。
起動コマンドから TCP SELECT 1 まで。取得時間は除外し、Devbox は初期化済みクラスタを使います。
DB を分離し、結合クエリを実行する時間の中央値。
ウォームアップ後に行う TCP 経由の検索。
20 万行を並べ替えて数える時間の中央値。
スキーマ準備後、クエリ前の値です。Docker と Testcontainers はコンテナ使用量(Testcontainers は PostgreSQL と Ryuk)と計測プロセスの増分を合算します。OrbStack VM の変化は別に示します。
同じ MB スケールですが、Go のリンク増分、圧縮イメージ、devbox の取得量で測る対象が異なります。
クエリ性能、計測方法、再現手順はベンチマークのページにあります。
本物の 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())import pgmem, psycopg
with pgmem.start(database="app") as pg: with psycopg.connect(pg.template.dsn) as conn: conn.execute("SELECT 1")try (Pgmem pg = Pgmem.builder().database("app").start(); Connection conn = DriverManager.getConnection(pg.template().jdbcUrl())) { conn.createStatement().execute("SELECT 1");}import { PgmemServer } from '@pgmem/core';import pg from 'pg';
await using server = await PgmemServer.start({ database: 'app' });const client = new pg.Client({ connectionString: server.url });