“Should we use a graph database or a relational database?” is one of the most common architecture questions, and it is often answered with slogans: graphs are for connected data, relational is for everything else. The useful answer is more specific. It comes down to how each model stores relationships, and therefore which queries each one makes cheap.
This post compares the two models on data modeling, querying, performance and operations, with runnable examples, and ends with a short checklist for choosing.
The short answer
- A relational database stores entities as rows in tables. Relationships are values (foreign keys) that a query matches up at run time with a join.
- A graph database stores entities as vertices and relationships as edges between them. A query traverses stored edges instead of computing matches.
If your important questions are about relationships, especially several hops deep or to an unknown depth, a graph database fits. If they are about sets of rows (totals, filters, reports) with shallow relationships, relational fits. Many applications have both kinds of question, which is why a database that offers both models in one engine is worth knowing about.
Data model: tables and keys vs vertices and edges
Take a small social network: people who know each other.
Relational model. Two tables. The relationship is a table of key pairs:
CREATE TABLE person (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE knows (from_id INTEGER REFERENCES person(id),
to_id INTEGER REFERENCES person(id));
A many-to-many relationship always needs a join table like knows. Any property of the relationship (when they met, how strong the tie is) becomes a column on that table.
Graph model. Two types: a vertex type for people and an edge type for the relationship. Properties can live on either.
CREATE VERTEX TYPE Person;
CREATE EDGE TYPE Knows;
CREATE VERTEX Person SET name = 'Alice';
CREATE VERTEX Person SET name = 'Bob';
CREATE EDGE Knows
FROM (SELECT FROM Person WHERE name = 'Alice')
TO (SELECT FROM Person WHERE name = 'Bob')
SET since = 2020;
That is SQL, running on ArcadeDB, which supports both SQL and the graph model. The edge is a record of its own, stored with links to the two vertices it connects, so the database never has to search for who Alice knows: it reads her edges.
Querying: joins vs traversals
Friends of friends (two hops) in relational SQL takes two joins on the link table plus joins back to person:
SELECT DISTINCT p3.name
FROM person p1
JOIN knows k1 ON k1.from_id = p1.id
JOIN knows k2 ON k2.from_id = k1.to_id
JOIN person p3 ON p3.id = k2.to_id
WHERE p1.name = 'Alice' AND p3.id <> p1.id;
In Cypher, the graph query language most graph databases support, the same question describes the path:
MATCH (a:Person {name: 'Alice'})-[:Knows*2]->(fof)
WHERE fof <> a
RETURN DISTINCT fof.name
Unknown depth is where the models really diverge. “Everyone Alice can reach through any chain of acquaintances” needs a recursive common table expression in SQL, which repeats a join on every iteration:
WITH RECURSIVE reach(id, depth) AS (
SELECT k.to_id, 1
FROM knows k JOIN person p ON p.id = k.from_id
WHERE p.name = 'Alice'
UNION
SELECT k.to_id, r.depth + 1
FROM reach r JOIN knows k ON k.from_id = r.id
WHERE r.depth < 5
)
SELECT DISTINCT p.name
FROM reach r JOIN person p ON p.id = r.id
WHERE p.name <> 'Alice';
In a graph database it is a variable-length pattern:
MATCH (a:Person {name: 'Alice'})-[:Knows*1..5]->(b)
RETURN DISTINCT b.name
And shortest path is a built-in function rather than an exercise in recursive SQL:
MATCH p = shortestPath(
(a:Person {name: 'Alice'})-[:Knows*]-(b:Person {name: 'Dave'}))
RETURN [n IN nodes(p) | n.name] AS names
The ArcadeDB query cheat sheet has these patterns and more in SQL, Cypher and Gremlin side by side.
Performance: why hops change everything
A join is computed: for each row on one side, the database finds matching rows on the other, typically through an index. Each additional hop is another join over the intermediate result, so the work grows with both the depth and the size of the tables involved.
A traversal reads relationships that are already stored with the record. The cost depends on how many edges the query actually touches, not on how large the tables are overall. That is why graph databases pull ahead on deep, branching queries and why the gap widens as hops increase.
We measured this directly on the LDBC Labelled Subgraph Query Benchmark, comparing ArcadeDB to PostgreSQL: across all nine queries ArcadeDB finished in 2.2 seconds against 69 seconds for PostgreSQL, and gaps of more than 150x on the two-hop friends-of-friends traversal and the star-shaped patterns. The full method, the queries and the caveats are in ArcadeDB vs PostgreSQL for graph queries.
The flip side is just as real: for scanning and aggregating one large table, or fetching a row by primary key, a relational database is excellent, and a graph database has no inherent advantage.
Schema and flexibility
Relational databases enforce a schema up front: every row of a table has the same columns, and changing the shape means a migration. That rigidity is a feature when data is regular and many applications share it.
Graph databases tend to be more flexible. In ArcadeDB, for example, Cypher and Gremlin create a type the first time you use a label, while SQL can declare properties, constraints and unique indexes when you want them enforced. You can start loose and tighten the schema as the model settles. Adding a new kind of relationship is a new edge type, not a new join table and a migration.
Transactions, tooling and maturity
Both families include ACID databases; ArcadeDB is fully ACID, and so are the major relational systems. Check this per product rather than per category.
Relational databases have decades of tooling: BI tools, ORMs, and a large pool of people who know SQL. Graph tooling is younger. Two things narrow that gap: graph databases that also speak SQL, and graph databases that implement the PostgreSQL wire protocol so existing drivers and tools can connect. ArcadeDB does both.
When to use a relational database
- Data is naturally tabular and regular.
- Relationships are shallow: one or two joins answer your questions.
- The workload is mostly aggregations, reports and CRUD by key.
- Your application depends on a specific relational product’s SQL dialect, stored procedures or extensions.
When to use a graph database
- The value is in the connections: fraud detection rings, recommendation engines that walk from users to items to similar users, identity and access management where permissions inherit through groups and roles.
- Queries need variable depth or paths: lineage, supply chains, network impact analysis.
- The model changes often and new relationship types appear over time, as in knowledge graphs.
- You are building AI retrieval that combines vector similarity with relationships, such as GraphRAG.
You do not always have to choose
Many systems have both kinds of question: an order table that needs monthly reports and a customer graph that needs traversals. The traditional answer was two databases and a pipeline to keep them in sync.
A multi-model database such as ArcadeDB stores tabular records, documents and graph edges in one engine, under one transaction, and lets you query them with SQL for reporting and Cypher or Gremlin for traversals. Our guide to what a multi-model database is explains the trade-offs of that approach.
ArcadeDB is open source under the Apache 2.0 license. The free ArcadeDB Academy has courses on both SQL and Cypher if you want to try the examples above hands-on.