Skip to main content

Graph Databases

Level 2: Level 2: Data Storage & Modelingmedium25 mingraph-dbneo4j

Index-free adjacency keeps deep traversals local while recursive SQL joins explode; a 1-2 hop adjacency table in SQL is often the simpler right choice.

Built for one thing: traversing relationships

A graph database (Neo4j, JanusGraph, Amazon Neptune, TigerGraph) models data as nodes (entities), edges (relationships), and properties on both. It is purpose-built for one thing: traversing relationships, especially deep, multi-hop ones. If your dominant queries are "friends of friends," "who influenced whom across 5 hops," "find the fraud ring connecting these accounts," or "recommend items bought by people who bought what you bought," a graph database is the right tool. If your queries are mostly "get this row by id" or "filter this table," it is the wrong tool.

Index-free adjacency

In a relational database, a relationship is a foreign key, and following it means a lookup (often an index seek into another table). Following it N times, a multi-hop traversal, means N joins, and each join can multiply the intermediate result set. In a native graph database, each node holds direct pointers to its adjacent edges and nodes. Traversing from a node to its neighbors is a pointer hop, roughly O(1) per step regardless of how big the total graph is, because you never consult a global index to find neighbors. The cost of a traversal is proportional to the portion of the graph you actually touch (the local neighborhood), not the size of the whole dataset. This is why "friends of friends of friends" stays fast in Neo4j while the equivalent 3-way self-join degrades in SQL.

Why recursive relational joins blow up. Friends-of-friends in SQL on a friendships(user_a, user_b) table: one hop is one self-join, two hops is a self-join of a self-join, and the intermediate result is roughly users times average degree squared. At depth 4 or 5 on a social graph with average degree 200+, intermediate rows explode into the billions and the optimizer chokes. The graph engine instead walks outward from the start node, visiting only reachable nodes, deduplicating as it goes.

Check yourself
Your app's only relationship query is 'show this user's direct friends', one hop, millions of times a day. Which store fits?

Query languages. Neo4j uses Cypher, an ASCII-art pattern language: MATCH (me:User {id:1})-[:FRIEND*1..2]-(fof) RETURN DISTINCT fof finds everyone 1 to 2 hops away. Gremlin (Apache TinkerPop) is the imperative traversal alternative, and GQL is the emerging standard. Knowing that -[:REL*1..3]- expresses variable-length paths is the interview-relevant literacy.

When you do NOT need a graph database

This is the senior judgment call. If your traversals are shallow (1 or 2 hops), a plain adjacency table in SQL with the right indexes is completely adequate and saves you a whole new datastore, its operational burden, and its scaling weaknesses. "Show a user's direct friends" is one indexed query. Only when depth grows, the patterns get variable-length, or path/relationship queries dominate does the graph engine earn its place.

Interview nuance: The tradeoff interviewers want you to name is horizontal scaling. Graphs are hard to shard because a good partition would cut edges, and the whole point is fast edge-following, so a traversal that crosses partitions pays a network hop per boundary and the index-free-adjacency advantage evaporates. Native graph databases often prefer to scale up (bigger machine, replicas for read scaling) rather than out. So the honest position is: graph databases are unbeatable for deep-traversal query complexity but weaker on raw horizontal write scale than Cassandra. Recommendation and fraud systems at extreme scale often precompute or use specialized graph-processing systems rather than a single serving graph database.

Recap: Graph databases win when relationships are first-class and traversals are deep, thanks to index-free adjacency that keeps traversal cost local; recursive SQL joins explode at depth, but a 1-to-2-hop adjacency table in SQL is often the right, simpler choice, and the graph engine's weakness is horizontal scaling.

Check yourself
A fraud team needs 'rings of accounts connected through shared devices and payment methods, up to 5 hops out'. Query volume is modest. What do you propose, and what caveat do you name unprompted?

Apply

Your turn

The task this lesson builds to.

Design the graph model for a social network's friends-of-friends and mutual-connection queries.

Think about

  1. Why do recursive relational joins blow up at traversal depth?
  2. What does index-free adjacency buy you?
  3. When does an adjacency table in SQL suffice instead?

Practice

Make it stick

A second problem on the same idea, so it survives past today.

Design the graph model for a payments company's real-time fraud-ring detection, where you must flag whether a new transaction connects (within 3 to 4 hops through shared devices, cards, IPs, and accounts) to a known fraudulent entity, at 10k transactions per second with a sub-100ms decision budget. Explain the model, the query, and how you meet the latency budget given graph scaling limits.

Think about

  1. What does a fraud ring look like structurally in a heterogeneous entity graph?
  2. Can a live 4-hop traversal per transaction hold a sub-100ms budget at 10k TPS?
  3. What can be precomputed offline so the hot path becomes a shallow lookup?