FalkorDB on Snowflake: Cypher vs SQL

FalkorDB on Snowflake Cypher vs SQL

Key Takeaways

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.

350,400 Airport nodes
5,063,700 ROUTE relationships

Snowflake tables

AIRPORTS_DEMO Airport entities
ROUTES_DEMO Directed airport-to-airport routes

Graph model

Airport ROUTE Airport
4-hop path shape
SFO a1 a2 a3 JFK

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.

Query SQL shape SQL time Cypher shape Cypher time
4-hop path SFO -> a1 -> a2 -> a3 -> JFK
8 joins
2.2s-2.6s
[:ROUTE*4]
1.3s-1.4s
5-hop path SFO -> a1 -> a2 -> a3 -> a4 -> JFK
10 joins
~30s
[:ROUTE*5]
~1.5s
6-hop path SFO -> a1 -> a2 -> a3 -> a4 -> a5 -> JFK
12 joins
Timed out
[:ROUTE*6]
~1.4s

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.