The supernode breaks the promise
A supernode's relationship chain is enormous, so expanding through it scans millions of edges and the O(1)-per-hop promise collapses on that single node — which is why you traverse from the low-degree side (The Rock has 232M inbound but few outbound) and group its edges by type and direction.
The planner anchors on the few, not the many — but what if the 'many' is unavoidable because a single node has millions of edges? That's a supernode, and expanding through its giant relationship chain scans millions of records: the O(1)-per-hop promise collapses on that one node. Reads are only half the damage, though — what happens when everyone tries to ADD an edge to that same celebrity at once?
Scene 09
The supernode breaks the promise
- Watch
- Try it
- Predict
- Capture
Two nodes, side by side. Erin has five relationship records — a normal node; a traversal that grazes her lights just a few neighbors. The Rock has so many followers that we can only draw a fan, each edge labeled ×10M (it really has ~232M). Watch a traversal try to expand INTO The Rock: it has to walk its entire relationship chain. The scan floods the fan… and stalls. It can't finish — every hop the curriculum promised was O(1) just turned into 'scan millions of edges' on this one node.
Highlighted lines are the ones running in the diagram right now.
def expand(node, rel_type, direction):out = []# walk the doubly-linked relationship chain for this siderel = node.first_rel(rel_type, direction)while rel is not None: # O(degree) — the whole costout.append(rel.other_end(node))rel = rel.next_in_chain # one pointer follow per edgereturn out# inbound on The Rock: ~232M iterations → drowns# outbound on The Rock: ~3 iterations → instant
def pick_expand_side(node, rel_type):# cost of a hop = how many edges hang off this sidein_deg = node.degree(rel_type, INBOUND)out_deg = node.degree(rel_type, OUTBOUND)# walk from the low-degree side — fewer pointer followsif in_deg <= out_deg:return INBOUNDreturn OUTBOUND# The Rock: in_deg ~232M, out_deg ~3 → pick OUTBOUND# (same node, opposite cost — degree, not the node, is the bill)
DENSE_THRESHOLD = 50 # ≥ this many edges → 'dense' layoutdef first_rel(node, rel_type, direction):if node.degree() < DENSE_THRESHOLD:return node.head_of_single_chain # one mixed chain# dense: jump straight to the right group's headgrp = node.group_record(rel_type, direction)return grp.chain_head # no scan to locate it# so EXPAND lands on the short chain directly,# never touching the giant one beside it
Where this sits in Build a graph database (Neo4j / Dgraph-style)
Scene 09 of 16, in the It breaks act — The supernode shatters the O(1)-per-hop promise.. A supernode is a vertex with a huge degree, and its relationship chain is so long that any traversal THROUGH it must scan millions of edges — so the O(1)-per-hop promise dies on that one node, and the fix is to expand from the low-degree side.
Up next. A supernode wrecks reads by being a long chain to scan. Now flip to writes: historically, adding an edge took a lock on the WHOLE node, so every concurrent 'follow The Rock' serialized on one lock and throughput collapsed. Fixing that needed a finer-grained lock — and it's a clean little half-step on the same supernode picture.
All 16 scenes in Build a graph database (Neo4j / Dgraph-style) · Every curriculum