Key Takeaways
- Graph-shaped logic, like multi-hop pathfinding, requires a graph-native query language (Cypher) to maintain query consistency, unlike SQL's structure which grows with traversal depth.
- Deploying FalkorDB within Snowflake allows graph analysis for workloads involving relationships without moving data outside the platform's security and governance boundary.
- Performance tests reveal a 6-hop path query on 5M edges timed out in SQL (12 joins) but completed in ~1.4s using Cypher's concise [:ROUTE*6] pattern.
Snowflake executes analytical SQL with high speed. However, some questions do not fit a tabular format. When you analyze relationships, paths, and multi-hop traversals, SQL typically requires a chain of repeated self-joins.
We evaluated this pattern by deploying FalkorDB within the Snowflake Native App environment. This test compares how multi-hop route queries perform and read in SQL versus Cypher.
The dataset
The test utilized the Air Routes dataset, which we loaded into FalkorDB from Snowflake tables.
The dataset
Air Routes loaded from Snowflake tables
The test utilized the Air Routes dataset, loaded into FalkorDB from Snowflake tables.
Snowflake tables
Graph model
The query pattern
The query identifies route paths from SFO to JFK.
For example, a 4-hop path looks like this:
SFO -> a1 -> a2 -> a3 -> JFK
This represents a graph-shaped problem. Architects should view this as following relationships from one airport to another through several intermediate points, rather than performing a simple table lookup.
Why SQL gets verbose
In this relational model, each route hop requires a join from an airport to a route and a subsequent join from that route to the next airport.
That means each hop requires:
Consequently, each hop requires:
1 join to ROUTES_DEMO
1 join to AIRPORTS_DEMO
The SQL join count grows as traversal depth increases:
Traversal depth | Path shape | SQL joins needed |
4 hops | SFO -> a1 -> a2 -> a3 -> JFK | 8 joins |
5 hops | SFO -> a1 -> a2 -> a3 -> a4 -> JFK | 10 joins |
6 hops | SFO -> a1 -> a2 -> a3 -> a4 -> a5 -> JFK | 12 joins |
For the 4-hop case, SQL has to spell out every hop manually:
SELECT
ARRAY_CONSTRUCT(sfo.code, a1.code, a2.code, a3.code, jfk.code) AS route_path
FROM FALKORDB_FLIGHTS_DEMO.PUBLIC.AIRPORTS_DEMO sfo
JOIN FALKORDB_FLIGHTS_DEMO.PUBLIC.ROUTES_DEMO r1 ON r1.source = sfo.id
JOIN FALKORDB_FLIGHTS_DEMO.PUBLIC.AIRPORTS_DEMO a1 ON a1.id = r1.target
JOIN FALKORDB_FLIGHTS_DEMO.PUBLIC.ROUTES_DEMO r2 ON r2.source = a1.id
JOIN FALKORDB_FLIGHTS_DEMO.PUBLIC.AIRPORTS_DEMO a2 ON a2.id = r2.target
JOIN FALKORDB_FLIGHTS_DEMO.PUBLIC.ROUTES_DEMO r3 ON r3.source = a2.id
JOIN FALKORDB_FLIGHTS_DEMO.PUBLIC.AIRPORTS_DEMO a3 ON a3.id = r3.target
JOIN FALKORDB_FLIGHTS_DEMO.PUBLIC.ROUTES_DEMO r4 ON r4.source = a3.id
JOIN FALKORDB_FLIGHTS_DEMO.PUBLIC.AIRPORTS_DEMO jfk ON jfk.id = r4.target
WHERE sfo.code = 'SFO' AND jfk.code = 'JFK'
LIMIT 50;
While functional, the SQL structure deviates from the logical question. SQL joins routes and airports repeatedly to reconstruct the path, whereas the intent is to find a traversal.
Why Cypher is more natural
Cypher maps the traversal directly to the query syntax:
MATCH path = (:Airport {code: 'SFO'})-[:ROUTE*4]->(:Airport {code: 'JFK'})
RETURN [airport IN nodes(path) | airport.code] AS route_path
LIMIT 50
The important part is:
[:ROUTE*4]
This instruction follows exactly four ROUTE relationships.
The query structure matches the question structure:
The query structure aligns with the functional requirement: find a route path from SFO to JFK with a length of 4 hops.
For deeper traversal, the Cypher stays nearly the same:
[:ROUTE*5]
[:ROUTE*6]
In SQL, every additional hop introduces two more joins. Cypher maintains a consistent structure regardless of depth.
Results observed
The following table details the timings from our test environment.
Results observed
SQL joins grow; Cypher keeps the traversal pattern compact
The following timings reflect the test environment described in the article.
These benchmarks reflect a specific test setup. Performance results vary based on warehouse configuration, compute resources, caching, and graph scale.
Snowflake handles analytical joins and set-based workloads effectively. The focus here is on architectural suitability.
Graph-shaped questions create structural complexity in SQL. As traversal depth increases, SQL queries grow longer and more difficult to maintain. Cypher keeps the query compact by treating path traversal as a native concept.
What this means for Snowflake users
Because FalkorDB is deployed as a Snowflake Native App, the user’s data never leaves the Snowflake security and governance boundary.
Deploying FalkorDB inside Snowflake allows architects to maintain data within the Snowflake ecosystem while utilizing graph-native queries for relationship-heavy workloads.
This approach supports several use cases:
- Which entities are connected within 3 to 6 hops?
- What paths exist between two known entities?
- Which accounts share phone numbers, addresses, or transactions?
- How do routes, dependencies, or relationships expand over several steps?
- Where do indirect relationships exist that are hard to express with standard joins?
SQL typically requires recursive logic or complex query generation for these scenarios. Cypher expresses the traversal directly as a path pattern. To sum up,
FalkorDB provides a graph-native layer within Snowflake for complex relationship analysis.
In our evaluation, a 4-hop query required 8 SQL joins compared to one Cypher pattern. As hop counts increased, the SQL overhead grew while the Cypher queries remained concise.
Architects can now implement graph-style analysis without moving data outside of their Snowflake environment.
References and citations
Markdown structured highlights and summary
### Reference
| Field | Value | Field | Value |
| --- | --- | --- | --- |
| Graph DB | FalkorDB | Deployment | Snowflake Native App |
| Platform | Snowflake | Dataset | Air Routes |
| Nodes | 350,400 Airport nodes | Relationships | 5,063,700 ROUTE relationships |
| Source tables | AIRPORTS_DEMO, ROUTES_DEMO | Domain | Multi-hop graph queries |
| Cypher form | [:RELATIONSHIP*N] | SQL form | Repeated self-joins |
### Benchmark
| Depth | SQL joins | SQL time | Cypher | Cypher time |
| --- | ---: | --- | --- | --- |
| 4 hops | 8 | 2.2s-2.6s | [:ROUTE*4] | 1.3s-1.4s |
| 5 hops | 10 | ~30s | [:ROUTE*5] | ~1.5s |
| 6 hops | 12 | Timed out | [:ROUTE*6] | ~1.4s |
**Finding:** SQL grows with hop depth; Cypher stays one traversal pattern inside Snowflake.