Performance and Benchmarks

PyGraphDB includes benchmark scripts for ingestion, traversal, sampling, RocksDB tuning, and an optional ArcadeDB comparison. Treat the included local results as directional examples, not universal claims.

Install Benchmark Dependencies

python -m pip install -e ".[leveldb,rocksdb,fast-ingest]"

Backend Benchmarks

Use benchmarks.py for a quick backend comparison on the same append-only workload.

python benchmarks.py --backend leveldb --nodes 20000 --edges 100000 --batch-size 10000 --append-only
python benchmarks.py --backend rocksdb --nodes 20000 --edges 100000 --batch-size 10000 --append-only

Use scripts/benchmark_matrix.py for larger matrix runs across graph sizes, backends, core counts, and ingestion modes.

uv run python scripts/benchmark_matrix.py \
   --sizes 10000 100000 1000000 \
   --cores 1 2 4 \
   --backends leveldb rocksdb \
   --ingestion-modes object arrow polars \
   --chunk-size 100000 \
   --samples 1000 \
   --sample-size 5 \
   --output-dir benchmark_results/matrix_YYYYMMDD

The matrix writes CSV and JSONL outputs and reopens the database before traversal workloads so traversal does not only measure Python-side object state.

Columnar Ingestion Benchmarks

Columnar ingestion accepts already-serialized node and edge payloads. With PyRexStore and pyrex-rocksdb>=0.3.0a0, RocksDB can use PyRex’s native write_columnar_batch path.

See notebooks/05_columnar_ingestion_benchmark.ipynb for a runnable example. A local run on 10,000 nodes and 50,000 edges with batch size 10,000 produced:

Mode

Node rate

Edge insert rate

LevelDB object batch

1,110,296/s

167,463 edges/s

RocksDB Arrow columnar native

1,035,690/s

265,050 edges/s

RocksDB Polars columnar native

929,044/s

250,517 edges/s

Larger append-only workloads with pre-serialized columnar payloads are expected to benefit more than small runs dominated by Python object construction.

RocksDB Tuning and Compaction Benchmarks

Use scripts/tune_rocksdb.py for a small RocksDB tuning matrix against a LevelDB baseline.

python scripts/tune_rocksdb.py --nodes 20000 --edges 100000 --batch-size 10000

Use scripts/benchmark_rocksdb_compaction.py for a repeated-overwrite workload that creates compaction pressure.

uv run python scripts/benchmark_rocksdb_compaction.py \
   --configs leveldb rocksdb-p1-bg1-smallbuf rocksdb-p4-bg4-smallbuf rocksdb-p8-bg8-smallbuf rocksdb-p4-bg4-largebuf \
   --keys 250000 \
   --passes 6 \
   --batch-size 5000 \
   --value-size 1024 \
   --output-dir benchmark_results/compaction_pressure_YYYYMMDD

A local run on 2026-06-25 produced:

Configuration

Backend

Initial write rate

Overwrite avg rate

Final SSTs

LevelDB

LevelDB

329,433 writes/s

114,663 writes/s

30

RocksDB p1/bg1 small buffer

RocksDB

694,105 writes/s

262,405 writes/s

14

RocksDB p4/bg4 small buffer

RocksDB

1,008,871 writes/s

749,948 writes/s

47

RocksDB p8/bg8 small buffer

RocksDB

987,248 writes/s

772,436 writes/s

17

RocksDB p4/bg4 large buffer

RocksDB

1,088,475 writes/s

1,132,815 writes/s

7

This workload favors RocksDB because it creates overlapping sorted runs that can benefit from background compaction parallelism. It should not be generalized to all graph workloads.

ArcadeDB Comparison Benchmarks

Use scripts/benchmark_arcadedb_vs_pygraphdb.py to compare PyGraphDB with the optional embedded ArcadeDB package. ArcadeDB is not required for normal PyGraphDB use.

Run a PyGraphDB-only smoke test:

uv run python scripts/benchmark_arcadedb_vs_pygraphdb.py \
   --engines pygraphdb \
   --nodes 10000 \
   --edges 50000 \
   --iterations 25 \
   --output-dir benchmark_results/arcadedb_vs_pygraphdb_YYYYMMDD

Include embedded ArcadeDB with uv --with:

uv run --with arcadedb-embedded python scripts/benchmark_arcadedb_vs_pygraphdb.py \
   --engines pygraphdb arcadedb \
   --workloads columnar_ingest star_traversal bfs_depth typed_path rocksdb_compaction \
   --nodes 100000 \
   --edges 500000 \
   --batch-size 100000 \
   --iterations 100 \
   --repetitions 10 \
   --output-dir benchmark_results/arcadedb_vs_pygraphdb_YYYYMMDD

The script writes raw rows and summary files grouped by engine and workload. If arcadedb-embedded is not installed, ArcadeDB rows are marked skipped and PyGraphDB rows still run.

Representative small local results from 2026-06-25:

Workload

PyGraphDB/RocksDB

ArcadeDB embedded

Relative result

columnar_ingest

0.0358 s

0.0506 s

PyGraphDB 1.41x faster

star_traversal

0.0383 s

0.0333 s

ArcadeDB 1.15x faster

bfs_depth

0.0303 s

0.0366 s

PyGraphDB 1.21x faster

typed_path

0.0293 s

0.0404 s

PyGraphDB 1.38x faster

rocksdb_compaction

0.0022 s

Not applicable

PyGraphDB only

Interpret these results by workload. RocksDB/PyGraphDB tends to show strength on append-only columnar ingestion and compaction-sensitive raw writes. ArcadeDB can be strongest when queries start from an indexed vertex and stay on native adjacency chains.

Benchmark Caveats

  • Local benchmark results depend on graph shape, storage device, CPU settings, Python version, backend versions, and warm-up behavior.

  • Small graphs can be dominated by Python object construction, serialization, and key construction rather than backend I/O.

  • Prefer raw CSV/JSONL outputs for comparisons and keep benchmark parameters with published results.