The dep_type becoming a relationship type instead of a property is the modeling decision worth sitting with longest. "Things you filter on want to be types, things you read afterward want to be properties" is a genuinely useful general rule, and it explains why query 3's AND d.dep_type = 'runtime' filter simply vanishes in Cypher, not because the graph is cleverer, but because the schema design moved a decision point from query-time to modeling-time, where it can't be silently forgotten.
The EXISTS comparison in query 7 is the sharpest technical point in the piece. LEFT JOIN ... IS NULL forces the relational engine to actually construct the non-matching rows just to prove they're empty, while EXISTS {} in Cypher can stop at the first match via the stored relationship degree, that's a real algorithmic difference, not just syntax sugar, and it's a good concrete answer to "is graph actually faster or just shorter" for at least this one query shape.
Query 10 is the honest center of the whole piece, and the FAQ's admission that the naive CTE "handled this nearly cycle-free dataset without drama" is the right caveat to include. The real argument isn't recursive-CTEs-are-bad, it's that reversing the traversal direction is a full second query you now maintain forever in SQL, versus flipping one arrow in Cypher, that's a maintenance-burden argument as much as a performance one, and it's more honest than claiming SQL simply can't do it.
The dep_type becoming a relationship type instead of a property is the modeling decision worth sitting with longest. "Things you filter on want to be types, things you read afterward want to be properties" is a genuinely useful general rule, and it explains why query 3's AND d.dep_type = 'runtime' filter simply vanishes in Cypher, not because the graph is cleverer, but because the schema design moved a decision point from query-time to modeling-time, where it can't be silently forgotten.
The EXISTS comparison in query 7 is the sharpest technical point in the piece. LEFT JOIN ... IS NULL forces the relational engine to actually construct the non-matching rows just to prove they're empty, while EXISTS {} in Cypher can stop at the first match via the stored relationship degree, that's a real algorithmic difference, not just syntax sugar, and it's a good concrete answer to "is graph actually faster or just shorter" for at least this one query shape.
Query 10 is the honest center of the whole piece, and the FAQ's admission that the naive CTE "handled this nearly cycle-free dataset without drama" is the right caveat to include. The real argument isn't recursive-CTEs-are-bad, it's that reversing the traversal direction is a full second query you now maintain forever in SQL, versus flipping one arrow in Cypher, that's a maintenance-burden argument as much as a performance one, and it's more honest than claiming SQL simply can't do it.