Loading a 117.2-million-relationship graph: Semurg 6.0 to 70.3 times faster than FalkorDB, ArcadeDB and SurrealDB
20 October 2026 · Semurg · 3 min read · Markdown
benchmarksgraphfalkordbarcadedbsurrealdbingestperformance
The first thing anyone does with a graph database is put a graph into it. A benchmark that only times queries leaves out the step that decides whether a team can reload its data every night or has to plan a weekend around it. Until now our graph results showed "Results pending" for every load: each engine had been loaded once, and one load is not a measurement. In our latest run every engine loaded the same graph repeatedly, from the same file, on the same server, and the benchmark page publishes the median.
The result
The graph is SNAP's com-Orkut social network: 117.2 million relationships between 3.07 million people[4]. As a server, Semurg loaded it in 23.6 s[1]. FalkorDB took 140.7 s[1], ArcadeDB 290.1 s[2] and SurrealDB 1,656.8 s[3], which is 6.0, 12.3 and 70.3 times as long as Semurg[1][2][3].
How the load was timed
- The same input for everyone: the graph file exactly as SNAP publishes it, staged once on the server; each engine read it with its own recommended bulk-load method, sized by its own tooling.
- Every engine maxed: each ran in Docker with every thread of the machine and both data disks, one engine at a time.
- A load is the whole load: the clock runs from an empty store until the engine says the whole graph is in, and the load is then checked by asking the same 4-hop question every engine must answer identically[4].
- Repeated, then the median: each load starts again from an empty store; the page shows the median and the spread.
What is not here yet
- Neo4j's and ArangoDB's load times are measured but not shown: for those two, our kit's timed load still includes a step of our own, so the figure would not be the engine's alone. They appear when the kit times their load by itself.
- FalkorDBLite's results are held for this run because of a counting mistake in our own kit, fixed in the kit published with this release; it is re-measured on the next run.
- The in-application load column is held for every engine in this run: Semurg's own load in that column went through its network connection, so it was not an in-application load.
Bigger than memory next
This graph fits in memory. The next run loads SNAP's com-Friendster, a social graph far larger than the memory each engine is given, where a load has to stream from disk without running out of room. Its results go on the benchmark page and into a post of their own.
Run it yourself
One command on a Linux machine with Docker runs the same graph, the same engines and the same checks: curl -fsSL https://one.semurg.io/bench | sudo bash -s -- --graph. Every load, query and walk, with its spread and every held row's reason, is on the benchmark page.
Evidence
- Benchmark Load the graph: Semurg 23569.0, falkordb 140676.0 (r11.118) (bench:graph/t1/server/falkordb@r11.118; the record as JSON)
- Benchmark Load the graph: Semurg 23569.0, arcadedb 290117.0 (r11.118) (bench:graph/t1/server/arcadedb@r11.118; the record as JSON)
- Benchmark Load the graph: Semurg 23569.0, surrealdb 1656756.0 (r11.118) (bench:graph/t1/server/surrealdb@r11.118; the record as JSON)
- Benchmark One query, 4 hops: Semurg 2.943, arcadedb 74.342 (r11.118) (bench:graph/t2/server/arcadedb@r11.118; the record as JSON)