Durabilità dei database misurati
Per queste misure delle prestazioni, tutti i database sono misurati in modalità persistente (dati scritti su disco, riprodotti al riavvio).
Database misurati
| Database | Versione misurata | Edizione o licenza | Protocollo | Misure |
|---|---|---|---|---|
| gDown | main @ 087a1a5, 2026-10-16 | JVM build, benchmark settings | Bolt | carichi |
| Neo4j | 5.26.31 community | Community (GPLv3) | Bolt | carichi |
| Memgraph | 3.13.1 | Community (BSL 1.1) | Bolt | carichi |
| FalkorDB | 0.0.1 on Redis 8.10.2 | SSPL 1.0 | RESP | carichi |
| ArcadeDB | 26.10.1 | Apache 2.0 | Bolt | carichi |
| TuGraph | 4.5.1 | Community (Apache 2.0) | Bolt | carichi |
| Apache AGE | 1.8.0 on PostgreSQL 18.6 (Debian 18.6-1.pgdg13+2) | Apache 2.0 (PostgreSQL extension) | JDBC | carichi |
Come gira il banco
| Proprietà | Valore |
|---|---|
| Architettura | arm64 |
| Macchina | Apple M4 Max, 16 logical CPUs, 64 GB RAM; Docker 29.8.2 |
| Limiti dei container | 4 CPU, 8 GB di memoria per container |
| Grafo dei carichi | 100,000 nodi, 1,000,000 relazioni, generati con un seme fisso |
| Giri | 3 giri completi; ogni cifra è la mediana dei giri |
| Client | Un client Java sull'host; 1, 4, 8 client concorrenti a seconda del carico |
| Protocollo | Il trasporto di ogni base (tabella sopra): Bolt da entrambe le parti per gDown e Neo4j; un giro di riscaldamento prima di ogni carico, non contato |
| Date | 2026-10-07 – 2026-10-15 |
Avvio, memoria, CPU e dimensione
Senza indice
| Carico | gDown | Neo4j | Memgraph | FalkorDB | ArcadeDB | TuGraph | Apache AGE |
|---|---|---|---|---|---|---|---|
| Avvio fino alla prima risposta | 0.6 | 4.2 | 1.4 | 0.8 | 2.5 | 1.5 | 1.9 |
| CPU media (100 % = un core) | 166 | 179 | 199 | 97 | 94 | 101 | 109 |
| CPU picco | 401 | 384 | 408 | 155 | 212 | 408 | 244 |
| Memoria picco | 519 | 4,814 | 538 | 436 | 6,425 | 374 | 477 |
| Dati su disco | 176 | 836 | 389 | 39 | 83 | 165 | 529 |
Con indici sugli identificatori
| Carico | gDown | Neo4j | Memgraph | FalkorDB | ArcadeDB | TuGraph | Apache AGE |
|---|---|---|---|---|---|---|---|
| Avvio fino alla prima risposta | 0.6 | 4.2 | 1.4 | 0.8 | 2.5 | 1.5 | 1.9 |
| CPU media (100 % = un core) | 141 | 180 | 193 | 97 | 94 | 101 | 109 |
| CPU picco | 397 | 380 | 412 | 154 | 212 | 408 | 244 |
| Memoria picco | 978 | 4,813 | 505 | 429 | 6,425 | 374 | 477 |
| Dati su disco | 182 | 837 | 389 | 39 | 83 | 165 | 529 |
Avvio: da docker run alla prima risposta a RETURN 1, mediana di più tentativi, misurato una volta e ripreso in entrambe le configurazioni; le altre righe coprono l'intera esecuzione dei carichi. CPU e disco non sono classificati: una base che non scrive nulla di durevole ha 0 MB su disco.
Letture complesse: latenza mediana — LDBC SNB Interactive
Le 29 query del carico Interactive del Social Network Benchmark dell'LDBC (14 letture complesse, 7 letture brevi, 8 aggiornamenti; Apache 2.0, invariate) girano tutte su un grafo generato con lo schema SNB.
- 29 / 29 query eseguite: 14 letture complesse, 7 brevi, 8 aggiornamenti
- 3 / 3 membri di un cluster a 3 nodi restituiscono lo stesso numero di righe per le 21 letture
- 18 ms mediana di una scrittura mentre il leader ne conferma 1.365 (3.000 persone)
- 0 ms mediana di una lettura su un follower durante queste scritture (95° percentile: 30 ms)
Tutti i database, 3,000 persone
| Carico | 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 trattino: la base rifiuta la query, supera il suo timeout o restituisce un numero di righe diverso da Neo4j (il suo tempo non significherebbe nulla). Caso per caso:
Tutti i database, 30,000 persone
- 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
Mediana su 5 persone dopo un giro di riscaldamento, un passaggio per base, in container limitati come nella tabella delle proprietà; ogni base è interrogata con il proprio trasporto (Bolt da entrambe le parti per gDown e Neo4j: l'andata e ritorno conta da entrambe le parti). «< 1 ms»: la mediana si arrotonda a zero millisecondi. Letture brevi: mediana sotto il millisecondo per gDown (da 0,5 a 0,7 ms) contro 0,7-1 ms per Neo4j, stesso protocollo da entrambe le parti.
Con 3.000 persone (90.000 nodi e 470.000 relazioni, caricati tramite Raft in 16 s), le mediane restano sotto i 60 ms. Due ottimizzazioni trovate da questo test: complex-1 è passata da 0,6 s a 34 ms, complex-14 da 2 s a 8 ms.
Risultati non ufficiali: queste cifre derivano dal carico LDBC SNB Interactive e non sono state verificate dal LDBC (Linked Data Benchmark Council). I dati sono generati dal test, non dal Datagen dell'LDBC: i tempi non sono confrontabili con i risultati LDBC pubblicati. Una sola esecuzione per configurazione. Il test ha anche trovato due difetti, ora corretti.
Fonte: gluonify-gdown, README e rapporti di LdbcSnbTest e LdbcClusterTest.
La copertura di Cypher (il TCK di openCypher su ogni base) è nella pagina di confronto.
Latenza e throughput, carico per carico
Stesso grafo, stesse query e stessa macchina per ogni base della tabella sopra: le cifre che seguono sono la mediana dei giri della tabella delle proprietà, misurate su arm64.
La latenza è la mediana (p50) in millisecondi, più basso è meglio; i carichi con più client sono in richieste al secondo, più alto è meglio. Il valore migliore di ogni riga è in grassetto. Nulla è regolato oltre i valori predefiniti di ogni immagine; gDown gira sulla JVM con un heap di 6 GB e una cache di pagine di 2 GB, Neo4j con un heap di 4 GB e una cache di pagine di 2 GB. Ogni esecuzione parte da un container nuovo, carica il grafo a lotti UNWIND, verifica che le basi concordino sui risultati, poi misura.
Senza indice
| Carico | gDown | Neo4j | Memgraph | FalkorDB | ArcadeDB | TuGraph | Apache AGE |
|---|---|---|---|---|---|---|---|
| Lettura per identificatore | 0.29 | 0.74 | 0.56 | 0.18 | 0.86 | 0.49 | 0.24 |
| Lettura per proprietà | 11.7 | 7.93 | 7.05 | 2.39 | 0.42 | 0.47 | 0.25 |
| Intervallo su una proprietà (100 valori) | 17.4 | 10.8 | 11.6 | 3.11 | 23.7 | 76.7 | 0.26 |
| Conteggio di un'etichetta | 0.38 | 0.74 | 4.03 | 0.19 | 0.46 | 97.9 | 9.37 |
| 1 salto | 0.28 | 0.52 | 0.40 | 0.19 | 0.40 | 0.51 | 0.27 |
| 2 salti distinti | 0.35 | 0.56 | 0.41 | 0.21 | 0.45 | 0.61 | 0.73 |
| 3 salti distinti | 0.88 | 1.17 | 0.71 | 0.34 | 1.07 | 1.37 | 5.61 |
| Raggruppamento + top 10 | 3.94 | 10.9 | 32.6 | 14.9 | 8.74 | 145 | 62.5 |
| Filtro + aggregato | 24.4 | 11.7 | 9.94 | 3.47 | 5.51 | 78.3 | 24.0 |
| Conteggio di un pattern (tutti i KNOWS tra persone) | 21.4 | 219 | 59.9 | 31.4 | 101 | 827 | 45.9 |
| Letture a caldo + un attraversamento completo ogni 100 | 0.32 | 0.57 | 0.41 | 0.19 | 0.41 | 0.53 | 0.31 |
| Prime 10 righe di un grande risultato | 0.33 | 0.59 | 0.46 | 0.20 | 0.60 | 0.56 | 0.21 |
| Scrittura: 1 nodo per richiesta | 0.47 | 0.57 | 0.57 | 0.35 | 0.56 | 0.49 | 0.26 |
| Scritture durante un lungo attraversamento | 0.66 | 0.54 | 0.71 | 35.0 | 0.80 | 0.60 | 0.28 |
| 8 client: 1 salto | 16,239 | 8,437 | 9,811 | 28,458 | 10,525 | 4,249 | 16,372 |
| 4 client: scritture | 6,801 | 5,223 | 3,260 | 4,652 | 3,364 | 3,675 | 9,280 |
ArcadeDB (indicizzato) è sempre misurato con indice: i suoi identificatori interni escludono la ricerca per id() usata per le altre colonne. La sua colonna è qui perché non manchi nulla, ma i suoi rapporti senza indice confrontano un indice con una scansione: vedere la tabella con indici per il confronto alla pari.
Con indici sugli identificatori
| Carico | gDown | Neo4j | Memgraph | FalkorDB | ArcadeDB | TuGraph | Apache AGE |
|---|---|---|---|---|---|---|---|
| Lettura per identificatore | 0.30 | 0.73 | 0.50 | 0.18 | 0.86 | 0.49 | 0.24 |
| Lettura per proprietà | 0.27 | 0.52 | 0.38 | 0.20 | 0.42 | 0.47 | 0.25 |
| Intervallo su una proprietà (100 valori) | 0.32 | 0.48 | 0.37 | 0.21 | 23.7 | 76.7 | 0.26 |
| Conteggio di un'etichetta | 0.26 | 0.46 | 3.77 | 0.17 | 0.46 | 97.9 | 9.37 |
| 1 salto | 0.26 | 0.46 | 0.34 | 0.19 | 0.40 | 0.51 | 0.27 |
| 2 salti distinti | 0.32 | 0.51 | 0.36 | 0.21 | 0.45 | 0.61 | 0.73 |
| 3 salti distinti | 0.82 | 1.00 | 0.51 | 0.33 | 1.07 | 1.37 | 5.61 |
| Raggruppamento + top 10 | 4.75 | 9.63 | 32.3 | 14.9 | 8.74 | 145 | 62.5 |
| Filtro + aggregato | 21.2 | 16.5 | 9.82 | 3.41 | 5.51 | 78.3 | 24.0 |
| Conteggio di un pattern (tutti i KNOWS tra persone) | 20.9 | 225 | 62.4 | 31.3 | 101 | 827 | 45.9 |
| Letture a caldo + un attraversamento completo ogni 100 | 0.32 | 0.54 | 0.40 | 0.19 | 0.41 | 0.53 | 0.31 |
| Prime 10 righe di un grande risultato | 0.34 | 0.55 | 0.46 | 0.21 | 0.60 | 0.56 | 0.21 |
| Scrittura: 1 nodo per richiesta | 0.42 | 0.55 | 0.59 | 0.36 | 0.56 | 0.49 | 0.26 |
| Scritture durante un lungo attraversamento | 0.66 | 0.56 | 0.60 | 35.0 | 0.80 | 0.60 | 0.28 |
| 8 client: 1 salto | 16,135 | 8,609 | 9,882 | 28,302 | 10,525 | 4,249 | 16,372 |
| 4 client: scritture | 6,842 | 5,192 | 3,314 | 4,423 | 3,364 | 3,675 | 9,280 |
Caricamento del grafo
Senza indice
| Carico | gDown | Neo4j | Memgraph | FalkorDB | ArcadeDB | TuGraph | Apache AGE |
|---|---|---|---|---|---|---|---|
| Tempo di caricamento | 6.4 | 8.8 | 4.9 | 5.8 | 15.2 | 110.5 | 99.0 |
| Velocità di caricamento | 172,107 | 125,063 | 224,642 | 188,301 | 72,488 | 9,954 | 11,115 |
Con indici sugli identificatori
| Carico | gDown | Neo4j | Memgraph | FalkorDB | ArcadeDB | TuGraph | Apache AGE |
|---|---|---|---|---|---|---|---|
| Tempo di caricamento | 10.9 | 11.0 | 6.0 | 40.8 | 15.2 | 110.5 | 99.0 |
| Velocità di caricamento | 101,280 | 99,864 | 183,114 | 26,988 | 72,488 | 9,954 | 11,115 |
Cosa ricavarne
- FalkorDB è il più veloce sulle operazioni brevi (letture per identificatore, salti, scrittura di un nodo) e nel throughput con più client, con il percorso client più corto (RESP). Guardate «scritture durante un lungo attraversamento»: le sue scritture aspettano dietro una lettura lunga; non scrive nulla di durevole per impostazione predefinita e il suo caricamento con indici è il più lento.
- gDown è più veloce di Neo4j sulla maggior parte dei carichi (media geometrica sotto 1 in entrambe le configurazioni), carica più in fretta e tiene i dati in molto meno spazio su disco. È pari o più lento sulle prime righe di un grande risultato e sulla scrittura di un nodo: vedete quelle righe.
- Rispetto a Memgraph, gDown vince su raggruppamenti, conteggi di etichetta e throughput con 8 client, e perde su letture brevi, salti e scritture. Memgraph non forza ogni volta i commit su disco, a differenza di gDown e Neo4j.
- ArcadeDB, misurato sempre con indice, è competitivo in lettura ma lento sugli intervalli e sulle scritture con più client.
- Memoria: i database che tengono tutto in RAM (Memgraph, FalkorDB) ne usano meno. gDown e Neo4j girano qui con heap generosi, e a gDown basta molto meno con un heap più piccolo per le stesse latenze (vedere la misura nativa più in alto).
Cosa questo confronto non dice
- La durabilità differisce: gDown e Neo4j sincronizzano il disco a ogni commit; Memgraph solo ogni 100 000 transazioni; FalkorDB non scrive nulla di durevole per impostazione predefinita; le impostazioni degli altri database non sono state verificate. Le righe di scrittura non confrontano quindi la stessa garanzia.
- I database che parlano Bolt condividono lo stesso driver Java; FalkorDB è misurato con un client RESP minimo scritto per il banco, che accorcia il suo percorso in lettura (vedere la colonna del trasporto).
- ArcadeDB è sempre misurato con indice, in entrambe le tabelle (i suoi identificatori interni escludono la ricerca per id()); un database senza valore in una configurazione non vi è stato misurato.
- Il grafo sta in memoria per tutti. Un grafo più grande della RAM, la replica, il failover, la ricerca vettoriale, gli algoritmi su grafo e le letture durante scritture concorrenti non sono misurati. Un solo nodo per database.
- ArcadeDB gira con un heap non limitato: la sua cifra di memoria non è confrontabile. La sua immagine è un'istantanea di sviluppo.
- Una macchina non a riposo, pochi giri: contate su ±10 % per ogni cella.
Fonte: gluonify-gdown, i risultati grezzi di ogni giro (docs/bench) e scripts/bench-compare.py, assemblati da uno script di questo sito; lo script del banco è nello stesso repository.