Durabilité des bases mesurées
Pour ces chiffres de performances, toutes les bases sont mesurées en mode persistant (données écrites sur disque, rejouées au redémarrage).
Bases mesurées
| Base | Version mesurée | Édition ou licence | Protocole | Mesures |
|---|---|---|---|---|
| gDown | main @ 087a1a5, 2026-10-16 | JVM build, benchmark settings | Bolt | charges |
| Neo4j | 5.26.31 community | Community (GPLv3) | Bolt | charges |
| Memgraph | 3.13.1 | Community (BSL 1.1) | Bolt | charges |
| FalkorDB | 0.0.1 on Redis 8.10.2 | SSPL 1.0 | RESP | charges |
| ArcadeDB | 26.10.1 | Apache 2.0 | Bolt | charges |
| TuGraph | 4.5.1 | Community (Apache 2.0) | Bolt | charges |
| Apache AGE | 1.8.0 on PostgreSQL 18.6 (Debian 18.6-1.pgdg13+2) | Apache 2.0 (PostgreSQL extension) | JDBC | charges |
Comment le banc tourne
| Propriété | Valeur |
|---|---|
| Architecture | arm64 |
| Machine | Apple M4 Max, 16 logical CPUs, 64 GB RAM; Docker 29.8.2 |
| Limites des conteneurs | 4 CPU, 8 Go de mémoire par conteneur |
| Graphe des charges | 100,000 nœuds, 1,000,000 relations, engendrés avec une graine fixe |
| Tours | 3 tours complets ; chaque chiffre est la médiane des tours |
| Clients | Un client Java sur l'hôte ; 1, 4, 8 clients concurrents selon la charge |
| Protocole | Le transport de chaque base (tableau ci-dessus) : Bolt des deux côtés pour gDown et Neo4j ; un tour de chauffe avant chaque charge, non compté |
| Dates | 2026-10-07 – 2026-10-15 |
Démarrage, mémoire, CPU et taille
Sans index
| Charge | gDown | Neo4j | Memgraph | FalkorDB | ArcadeDB | TuGraph | Apache AGE |
|---|---|---|---|---|---|---|---|
| Démarrage jusqu'à la première réponse | 0.6 | 4.2 | 1.4 | 0.8 | 2.5 | 1.5 | 1.9 |
| CPU moyen (100 % = un cœur) | 166 | 179 | 199 | 97 | 94 | 101 | 109 |
| CPU crête | 401 | 384 | 408 | 155 | 212 | 408 | 244 |
| Mémoire crête | 519 | 4,814 | 538 | 436 | 6,425 | 374 | 477 |
| Données sur disque | 176 | 836 | 389 | 39 | 83 | 165 | 529 |
Avec index sur les identifiants
| Charge | gDown | Neo4j | Memgraph | FalkorDB | ArcadeDB | TuGraph | Apache AGE |
|---|---|---|---|---|---|---|---|
| Démarrage jusqu'à la première réponse | 0.6 | 4.2 | 1.4 | 0.8 | 2.5 | 1.5 | 1.9 |
| CPU moyen (100 % = un cœur) | 141 | 180 | 193 | 97 | 94 | 101 | 109 |
| CPU crête | 397 | 380 | 412 | 154 | 212 | 408 | 244 |
| Mémoire crête | 978 | 4,813 | 505 | 429 | 6,425 | 374 | 477 |
| Données sur disque | 182 | 837 | 389 | 39 | 83 | 165 | 529 |
Démarrage : du docker run à la première réponse à RETURN 1, médiane de plusieurs essais, mesuré une fois et repris dans les deux configurations ; les autres lignes couvrent toute l'exécution des charges. Le CPU et le disque ne sont pas classés : une base qui n'écrit rien de durable a 0 Mo sur disque.
Lectures complexes : latence médiane — LDBC SNB Interactive
Les 29 requêtes de la charge Interactive du Social Network Benchmark du LDBC (14 lectures complexes, 7 lectures courtes, 8 mises à jour ; Apache 2.0, inchangées) tournent toutes sur un graphe engendré au schéma SNB.
- 29 / 29 requêtes exécutées : 14 lectures complexes, 7 lectures courtes, 8 mises à jour
- 3 / 3 membres d'un cluster à 3 nœuds renvoient les mêmes nombres de lignes pour les 21 lectures
- 18 ms médiane d'une écriture pendant que le leader en acquitte 1 365 (3 000 personnes)
- 0 ms médiane d'une lecture sur un suiveur pendant ces écritures (95e centile : 30 ms)
Toutes les bases, 3,000 personnes
| Charge | gDown | Neo4j | Memgraph | FalkorDB | ArcadeDB | TuGraph | Apache AGE |
|---|---|---|---|---|---|---|---|
| complex-1 | 2.3 | 7.5 | – | – | 12.3 | – | – |
| complex-2 | 1.2 | 2.4 | 3.8 | 209.0 | 3.3 | – | – |
| complex-3 | 9.0 | 10.3 | 8.9 | – | 19.5 | – | – |
| complex-4 | 0.9 | 2.2 | 1.1 | 0.6 | 2.5 | – | 126.1 |
| complex-5 | 4.7 | 10.1 | 4.9 | 2.5 | 16169.2 | – | – |
| complex-6 | 4.1 | 5.3 | 2.6 | – | 10.4 | – | – |
| complex-7 | 0.8 | 2.1 | 1.4 | – | – | – | – |
| complex-8 | 0.6 | 1.5 | 1.6 | 0.6 | 1.7 | – | – |
| complex-9 | 6.0 | 5.8 | 16.9 | – | 16.6 | – | – |
| complex-10 | 1.1 | 4.8 | – | – | – | – | – |
| complex-11 | 0.9 | 2.4 | 1.4 | 0.6 | 2.5 | – | – |
| complex-12 | 1.7 | 2.6 | 4.4 | – | 3.1 | – | – |
| complex-13 | 0.9 | 1.6 | – | – | 1.2 | – | – |
| complex-14 | 0.8 | 2.2 | – | – | 1861.0 | – | – |
Un tiret : la base refuse la requête, dépasse son délai ou renvoie un nombre de lignes différent de Neo4j (son temps ne voudrait rien dire). Cas par cas :
Toutes les bases, 30,000 personnes
- complex-1 : gDown 12.9 ms, Neo4j 51.5 ms
- complex-2 : gDown 2.8 ms, Neo4j 2 ms
- complex-3 : gDown 15.1 ms, Neo4j 13.3 ms
- complex-4 : gDown 1.6 ms, Neo4j 1.7 ms
- complex-5 : gDown 19.5 ms, Neo4j 16.9 ms
- complex-6 : gDown 6.7 ms, Neo4j 7 ms
- complex-7 : gDown 1.4 ms, Neo4j 1.4 ms
- complex-8 : gDown 0.8 ms, Neo4j 1 ms
- complex-9 : gDown 15.1 ms, Neo4j 8.5 ms
- complex-10 : gDown 4.4 ms, Neo4j 4.2 ms
- complex-11 : gDown 1.9 ms, Neo4j 1.8 ms
- complex-12 : gDown 2 ms, Neo4j 2.4 ms
- complex-13 : gDown 0.9 ms, Neo4j 1 ms
- complex-14 : gDown 4 ms, Neo4j 3.3 ms
Médiane sur 5 personnes après un tour de chauffe, un passage par base, dans des conteneurs limités comme dans le tableau des propriétés ; chaque base est interrogée par son transport (Bolt des deux côtés pour gDown et Neo4j : l'aller-retour est compté des deux côtés). « < 1 ms » : la médiane s'arrondit à zéro milliseconde. Lectures courtes : médiane sous la milliseconde pour gDown (0,5 à 0,7 ms) contre 0,7 à 1 ms pour Neo4j, même protocole des deux côtés.
À 3 000 personnes (90 000 nœuds et 470 000 relations, chargés par Raft en 16 s), les médianes restent sous 60 ms. Deux optimisations trouvées par ce test : complex-1 est passée de 0,6 s à 34 ms, complex-14 de 2 s à 8 ms.
Résultats non officiels : ces chiffres sont dérivés de la charge LDBC SNB Interactive et n’ont pas été audités par le LDBC (Linked Data Benchmark Council). Les données sont engendrées par le test, pas par le Datagen du LDBC : les temps ne sont pas comparables aux résultats LDBC publiés. Une seule exécution par configuration. Le test a aussi trouvé deux défauts, corrigés.
Source : gluonify-gdown, README et rapports de LdbcSnbTest et LdbcClusterTest.
La couverture de Cypher (le TCK openCypher sur chaque base) est sur la page de comparaison.
Latence et débit, charge par charge
Même graphe, mêmes requêtes et même machine pour chaque base du tableau ci-dessus : les chiffres ci-dessous sont la médiane des tours du tableau des propriétés, mesurés sur arm64.
La latence est la médiane (p50) en millisecondes, plus bas = mieux ; les charges à plusieurs clients sont en requêtes par seconde, plus haut = mieux. La meilleure valeur de chaque ligne est en gras. Rien n'est réglé au-delà des défauts de chaque image ; gDown tourne sur la JVM avec un tas de 6 Go et un cache de pages de 2 Go, Neo4j avec un tas de 4 Go et un cache de pages de 2 Go. Chaque exécution part d'un conteneur neuf, charge le graphe par lots UNWIND, vérifie que les bases s'accordent sur les résultats, puis mesure.
Sans index
| Charge | gDown | Neo4j | Memgraph | FalkorDB | ArcadeDB | TuGraph | Apache AGE |
|---|---|---|---|---|---|---|---|
| Lecture par identifiant | 0.29 | 0.74 | 0.56 | 0.18 | 0.86 | 0.49 | 0.24 |
| Lecture par propriété | 11.7 | 7.93 | 7.05 | 2.39 | 0.42 | 0.47 | 0.25 |
| Intervalle sur une propriété (100 valeurs) | 17.4 | 10.8 | 11.6 | 3.11 | 23.7 | 76.7 | 0.26 |
| Comptage d'une étiquette | 0.38 | 0.74 | 4.03 | 0.19 | 0.46 | 97.9 | 9.37 |
| 1 saut | 0.28 | 0.52 | 0.40 | 0.19 | 0.40 | 0.51 | 0.27 |
| 2 sauts distincts | 0.35 | 0.56 | 0.41 | 0.21 | 0.45 | 0.61 | 0.73 |
| 3 sauts distincts | 0.88 | 1.17 | 0.71 | 0.34 | 1.07 | 1.37 | 5.61 |
| Regroupement + top 10 | 3.94 | 10.9 | 32.6 | 14.9 | 8.74 | 145 | 62.5 |
| Filtre + agrégat | 24.4 | 11.7 | 9.94 | 3.47 | 5.51 | 78.3 | 24.0 |
| Comptage d'un motif (tous les KNOWS entre personnes) | 21.4 | 219 | 59.9 | 31.4 | 101 | 827 | 45.9 |
| Lectures chaudes + un parcours complet pour 100 | 0.32 | 0.57 | 0.41 | 0.19 | 0.41 | 0.53 | 0.31 |
| 10 premières lignes d'un grand résultat | 0.33 | 0.59 | 0.46 | 0.20 | 0.60 | 0.56 | 0.21 |
| Écriture : 1 nœud par requête | 0.47 | 0.57 | 0.57 | 0.35 | 0.56 | 0.49 | 0.26 |
| Écritures pendant un long parcours | 0.66 | 0.54 | 0.71 | 35.0 | 0.80 | 0.60 | 0.28 |
| 8 clients : 1 saut | 16,239 | 8,437 | 9,811 | 28,458 | 10,525 | 4,249 | 16,372 |
| 4 clients : écritures | 6,801 | 5,223 | 3,260 | 4,652 | 3,364 | 3,675 | 9,280 |
ArcadeDB (indexé) est toujours mesuré avec index : ses identifiants internes interdisent la recherche par id() des autres colonnes. Sa colonne est ici pour que rien ne manque, mais ses rapports sans index comparent un index à un parcours : voir le tableau avec index pour la comparaison à armes égales.
Avec index sur les identifiants
| Charge | gDown | Neo4j | Memgraph | FalkorDB | ArcadeDB | TuGraph | Apache AGE |
|---|---|---|---|---|---|---|---|
| Lecture par identifiant | 0.30 | 0.73 | 0.50 | 0.18 | 0.86 | 0.49 | 0.24 |
| Lecture par propriété | 0.27 | 0.52 | 0.38 | 0.20 | 0.42 | 0.47 | 0.25 |
| Intervalle sur une propriété (100 valeurs) | 0.32 | 0.48 | 0.37 | 0.21 | 23.7 | 76.7 | 0.26 |
| Comptage d'une étiquette | 0.26 | 0.46 | 3.77 | 0.17 | 0.46 | 97.9 | 9.37 |
| 1 saut | 0.26 | 0.46 | 0.34 | 0.19 | 0.40 | 0.51 | 0.27 |
| 2 sauts distincts | 0.32 | 0.51 | 0.36 | 0.21 | 0.45 | 0.61 | 0.73 |
| 3 sauts distincts | 0.82 | 1.00 | 0.51 | 0.33 | 1.07 | 1.37 | 5.61 |
| Regroupement + top 10 | 4.75 | 9.63 | 32.3 | 14.9 | 8.74 | 145 | 62.5 |
| Filtre + agrégat | 21.2 | 16.5 | 9.82 | 3.41 | 5.51 | 78.3 | 24.0 |
| Comptage d'un motif (tous les KNOWS entre personnes) | 20.9 | 225 | 62.4 | 31.3 | 101 | 827 | 45.9 |
| Lectures chaudes + un parcours complet pour 100 | 0.32 | 0.54 | 0.40 | 0.19 | 0.41 | 0.53 | 0.31 |
| 10 premières lignes d'un grand résultat | 0.34 | 0.55 | 0.46 | 0.21 | 0.60 | 0.56 | 0.21 |
| Écriture : 1 nœud par requête | 0.42 | 0.55 | 0.59 | 0.36 | 0.56 | 0.49 | 0.26 |
| Écritures pendant un long parcours | 0.66 | 0.56 | 0.60 | 35.0 | 0.80 | 0.60 | 0.28 |
| 8 clients : 1 saut | 16,135 | 8,609 | 9,882 | 28,302 | 10,525 | 4,249 | 16,372 |
| 4 clients : écritures | 6,842 | 5,192 | 3,314 | 4,423 | 3,364 | 3,675 | 9,280 |
Chargement du graphe
Sans index
| Charge | gDown | Neo4j | Memgraph | FalkorDB | ArcadeDB | TuGraph | Apache AGE |
|---|---|---|---|---|---|---|---|
| Temps de chargement | 6.4 | 8.8 | 4.9 | 5.8 | 15.2 | 110.5 | 99.0 |
| Débit de chargement | 172,107 | 125,063 | 224,642 | 188,301 | 72,488 | 9,954 | 11,115 |
Avec index sur les identifiants
| Charge | gDown | Neo4j | Memgraph | FalkorDB | ArcadeDB | TuGraph | Apache AGE |
|---|---|---|---|---|---|---|---|
| Temps de chargement | 10.9 | 11.0 | 6.0 | 40.8 | 15.2 | 110.5 | 99.0 |
| Débit de chargement | 101,280 | 99,864 | 183,114 | 26,988 | 72,488 | 9,954 | 11,115 |
Ce qu'il faut en retenir
- FalkorDB est le plus rapide sur les opérations courtes (lectures par identifiant, sauts, écriture d'un nœud) et en débit à plusieurs clients, avec le chemin client le plus court (RESP). Regardez « écritures pendant un long parcours » : ses écritures attendent derrière une lecture longue ; il n'écrit rien de durable par défaut et son chargement avec index est le plus lent.
- gDown est plus rapide que Neo4j sur la plupart des charges (moyenne géométrique sous 1 dans les deux configurations), charge plus vite et garde ses données dans bien moins d'espace disque. Il est égal ou plus lent sur les premières lignes d'un grand résultat et sur l'écriture d'un nœud : voyez ces lignes.
- Face à Memgraph, gDown gagne sur les regroupements, les comptages d'étiquette et le débit à 8 clients, et perd sur les lectures courtes, les sauts et les écritures. Memgraph ne force pas ses validations sur disque à chaque fois, contrairement à gDown et Neo4j.
- ArcadeDB, toujours mesuré avec index, est compétitif en lecture mais lent sur les intervalles et sur les écritures à plusieurs clients.
- Mémoire : les bases qui gardent tout en mémoire vive (Memgraph, FalkorDB) en utilisent le moins. gDown et Neo4j tournent ici avec des tas généreux, et gDown se contente de bien moins avec un tas plus petit pour les mêmes latences (voir la mesure native plus haut).
Ce que cette comparaison ne dit pas
- La durabilité diffère : gDown et Neo4j synchronisent le disque à chaque validation ; Memgraph seulement tous les 100 000 transactions ; FalkorDB n'écrit rien de durable par défaut ; les réglages des autres bases n'ont pas été vérifiés. Les lignes d'écriture ne comparent donc pas la même garantie.
- Les bases qui parlent Bolt partagent le même pilote Java ; FalkorDB est mesuré avec un client RESP minimal écrit pour le banc, qui raccourcit son chemin en lecture (voir la colonne transport).
- ArcadeDB est toujours mesuré avec index, dans les deux tableaux (ses identifiants internes interdisent la recherche par id()) ; une base sans valeur dans une configuration n'y a pas été mesurée.
- Le graphe tient en mémoire pour toutes les bases. Un graphe plus grand que la RAM, la réplication, la reprise après panne, la recherche vectorielle, les algorithmes de graphe et les lectures pendant des écritures concurrentes ne sont pas mesurés. Un seul nœud de chaque base.
- ArcadeDB tourne avec un tas non borné : son chiffre de mémoire n'est pas comparable. Son image est un instantané de développement.
- Une machine qui n'était pas au repos, quelques tours : comptez ±10 % sur chaque cellule.
Source : gluonify-gdown, les résultats bruts de chaque tour (docs/bench) et scripts/bench-compare.py, assemblés par un script de ce site ; le script du banc est dans le même dépôt.