Skip to content

Performance

Mabat runs one query for the root rows and one batched query per relationship, then decodes the rows into nested values. How much does that cost against writing the same queries by hand, or against other Rust database libraries? The benchmark in benches/orm-comparison loads the same data four ways and measures it with criterion.

Tasks by key, each with its 10 subtasks in order of their position, as typed nested values: 1, 100 and 10,000 tasks out of 10,000. Each library loads them its own idiomatic, batched way, two queries and grouping in Rust, on one connection:

How it loads
SQLx, by handWHERE id = ANY($1), then WHERE task_id = ANY($1) ORDER BY position, grouped in a HashMap
Mabatmabat::load::<Task>().by_keys(keys).all(&mut conn), with a child collection
SeaORM 2.0Task::find().filter(id.is_in(keys)), then load_many of the subtasks ordered by position
diesel-async 0.9eq_any(keys), then belonging_to(&tasks).order(position) and grouped_by

Median of criterion’s samples, on an Apple M1 with 8 GB, PostgreSQL 16.9 on the same machine, Rust 1.96, SQLx 0.9.0, SeaORM 2.0.4, Diesel 2.3.14 with diesel-async 0.9.2 and tokio-postgres 0.7.18:

Tasks (× 10 subtasks)SQLx, by handMabatSeaORMdiesel-async
186.6 µs98.9 µs191.9 µs101.1 µs
100897 µs964 µs957 µs594 µs
10,00074.3 ms80.6 ms79.3 ms47.0 ms
  • Mabat is within 7–14% of hand-written SQLx running the same two queries, the cost of planning the load and decoding by alias into nested values.
  • Against SeaORM, Mabat is about as fast for 100 and 10,000 tasks, and twice as fast for one.
  • diesel-async is 35–40% faster than all three for many rows. It runs on the tokio-postgres driver; the others run on SQLx. Hand-written SQLx is as far behind it as Mabat is, so the difference is the driver’s, not the mapping’s.
Terminal window
cd benches/orm-comparison
../../scripts/with-postgres.sh sh -c 'DATABASE_URL=$MABAT_TEST_DATABASE_URL cargo bench'

It needs the PostgreSQL server binaries, as the tests do, fills the database of DATABASE_URL with 10,000 tasks and 100,000 subtasks, and checks that every library loads the same counts before measuring. The crate is a workspace of its own, so building Mabat never compiles SeaORM or Diesel. Results depend on the machine and on where the database runs: on a network, round trips dominate and the four come closer together.