Compare PRO#
The compare command runs the same workload against two databases simultaneously and compares performance. It answers “is Postgres or MySQL faster for my workload?” in one command.
Each database gets its own config file with driver-specific SQL. Both configs should have matching query names so the TUI can show side-by-side results per query.
Subcommands#
| Command | Description |
|---|---|
compare up | Create schema on both databases |
compare seed | Populate tables on both databases |
compare run | Run workload on both databases simultaneously |
compare deseed | Delete seeded data from both databases |
compare down | Tear down schema on both databases |
compare all | Run up, seed, run, deseed, and down on both databases |
Flags#
Connection flags#
These persistent flags apply to all compare subcommands:
| Flag / Env Var | Default | Description |
|---|---|---|
--a-driverEDG_COMPARE_A_DRIVER | pgx | Database driver for side A (pgx, mysql, mongodb, cassandra, mssql, oracle, dsql, spanner) |
--a-urlEDG_COMPARE_A_URL | Database connection URL for side A | |
--a-configEDG_COMPARE_A_CONFIG | Path to the edg config file for side A | |
--b-driverEDG_COMPARE_B_DRIVER | pgx | Database driver for side B (pgx, mysql, mongodb, cassandra, mssql, oracle, dsql, spanner) |
--b-urlEDG_COMPARE_B_URL | Database connection URL for side B | |
--b-configEDG_COMPARE_B_CONFIG | Path to the edg config file for side B |
Run flags#
These flags are specific to compare run and compare all:
| Flag | Short | Default | Description |
|---|---|---|---|
--duration | -d | 1m | Benchmark duration |
--workers | -w | 1 | Number of concurrent workers per database. Values greater than 1 require a pro license. PRO |
--print-interval | 1s | Progress reporting interval | |
--warmup-duration | 0 | Warmup period before collecting metrics. Workers run during warmup but results are discarded. |
Example#
This example references the compare example and targets Postgres and MySQL using identical schemas with 1,000 users and 5,000 orders.
Setup#
docker compose -f infra/compose_postgres.yml up -d
docker compose -f infra/compose_mysql.yml up -d
until psql "postgres://root:password@localhost:5432/defaultdb" -c "SELECT 1" &>/dev/null; do sleep 1; done
until mysql -u root -ppassword -h 127.0.0.1 -e "SELECT 1" &>/dev/null 2>&1; do sleep 1; doneAll-in-one#
edg compare all \
--a-driver pgx \
--a-url "postgres://root:password@localhost:5432/defaultdb?sslmode=disable" \
--a-config examples/compare/postgres.yaml \
--b-driver mysql \
--b-url "root:password@tcp(localhost:3306)/defaultdb?parseTime=true" \
--b-config examples/compare/mysql.yaml \
--rng-seed 42 \
-w 4 \
-d 30s \
--tuiStep-by-step#
edg compare up \
--a-driver pgx \
--a-url "postgres://root:password@localhost:5432/defaultdb?sslmode=disable" \
--a-config examples/compare/postgres.yaml \
--b-driver mysql \
--b-url "root:password@tcp(localhost:3306)/defaultdb?parseTime=true" \
--b-config examples/compare/mysql.yaml
edg compare seed \
--a-driver pgx \
--a-url "postgres://root:password@localhost:5432/defaultdb?sslmode=disable" \
--a-config examples/compare/postgres.yaml \
--b-driver mysql \
--b-url "root:password@tcp(localhost:3306)/defaultdb?parseTime=true" \
--b-config examples/compare/mysql.yaml \
--rng-seed 42
edg compare run \
--a-driver pgx \
--a-url "postgres://root:password@localhost:5432/defaultdb?sslmode=disable" \
--a-config examples/compare/postgres.yaml \
--b-driver mysql \
--b-url "root:password@tcp(localhost:3306)/defaultdb?parseTime=true" \
--b-config examples/compare/mysql.yaml \
-w 4 \
-d 30s \
--tuiTeardown#
edg compare down \
--a-driver pgx \
--a-url "postgres://root:password@localhost:5432/defaultdb?sslmode=disable" \
--a-config examples/compare/postgres.yaml \
--b-driver mysql \
--b-url "root:password@tcp(localhost:3306)/defaultdb?parseTime=true" \
--b-config examples/compare/mysql.yaml
docker compose -f infra/compose_postgres.yml down
docker compose -f infra/compose_mysql.yml downTUI#
Add --tui to compare run or compare all for an interactive side-by-side view.
Log view#
A single merged table with separate header rows for each database:
00:15 / 00:30
A - pgx
QUERY COUNT ERRORS AVG p50 p95 p99 QPS
lookup_user 1200 0 1.2ms 1.0ms 2.1ms 3.4ms 80.0
list_orders 1180 0 2.3ms 2.0ms 4.1ms 6.2ms 78.7
insert_order 240 0 3.1ms 2.8ms 5.2ms 7.8ms 16.0
B - mysql
QUERY COUNT ERRORS AVG p50 p95 p99 QPS
lookup_user 980 0 2.4ms 2.1ms 4.3ms 6.8ms 65.3
list_orders 960 0 3.8ms 3.4ms 6.9ms 10.1ms 64.0
insert_order 195 0 5.2ms 4.8ms 8.4ms 12.3ms 13.0Graph view#
Press Tab to switch to the graph view. Both databases’ series are overlaid on a single chart with distinct color families. Series names are prefixed with “A:” and “B:”.
Keyboard controls#
Same as the standard TUI: Tab toggles log/graph, arrow keys navigate, 1-9 focus a series, q or Esc quits.
Text mode#
Without --tui, progress prints to stdout at each --print-interval. After the run completes, a summary shows per-query stats for both databases with delta percentages:
summary
Duration: 30.001s
Workers: 4
A - pgx
QUERY COUNT ERRORS AVG p50 p95 p99 QPS
lookup_user 2400 0 1.2ms 1.0ms 2.1ms 3.4ms 80.0
list_orders 2360 0 2.3ms 2.0ms 4.1ms 6.2ms 78.7
insert_order 480 0 3.1ms 2.8ms 5.2ms 7.8ms 16.0
B - mysql
QUERY COUNT ERRORS AVG p50 p95 p99 QPS
lookup_user 1960 0 2.4ms 2.1ms 4.3ms 6.8ms 65.3
list_orders 1920 0 3.8ms 3.4ms 6.9ms 10.1ms 64.0
insert_order 390 0 5.2ms 4.8ms 8.4ms 12.3ms 13.0
delta (B vs A)
QUERY AVG p50 p95 p99 QPS
lookup_user +100.0% +110.0% +104.8% +100.0% -18.4%
list_orders +65.2% +70.0% +68.3% +62.9% -18.7%
insert_order +67.7% +71.4% +61.5% +57.7% -18.8%Positive deltas in latency columns mean B is slower. Negative deltas in QPS mean B has lower throughput.
Config requirements#
Compare configs differ from sync configs in one key way: they must include a run section with benchmark queries.
- Matching query names: Use the same
name:values in both configs so results align in the TUI - Matching weights: Use the same
weight:values so the workload mix is comparable - Driver-specific SQL: Adapt placeholder syntax (
$1for pgx,?for mysql) and dialect differences (ON CONFLICTvsON DUPLICATE KEY) - Same globals: Use identical
globalsvalues for consistent seeding