You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A redundant type(r) = 'P' check makes a statically typed relationship query about 6x slower #2481
A redundant type(r) = 'P' check makes a statically typed relationship query about 6x slower
I found that adding WHERE type(r) = 'P' to a relationship already matched as [r:P] makes the query about six times slower. The condition is always true, and both queries return the same count.
Apache AGE Version: 1.7.0
PostgreSQL Version: 18.1
Operating System: macOS 27.0 arm64
Installation Method: official apache/age Docker image
LOAD 'age';
SET search_path = ag_catalog, "$user", public;
SELECTag_catalog.create_graph('relationship_type_guard_perf');
Create 20,000 relationships of type P:
SELECT*FROMag_catalog.cypher('relationship_type_guard_perf', $$
UNWIND range(1, 20000) AS i
CREATE (:X {id: i})-[:P {id: i}]->(:Y {id: i})
RETURN count(*) AS created
$$) AS (created agtype);
SELECT*FROMag_catalog.cypher('relationship_type_guard_perf', $$
MATCH (:X)-[r:P]->(:Y)
RETURN count(*) AS c
$$) AS (c agtype);
Run query B, which only adds a condition already guaranteed by [r:P]:
SELECT*FROMag_catalog.cypher('relationship_type_guard_perf', $$
MATCH (:X)-[r:P]->(:Y)
WHERE type(r) ='P'
RETURN count(*) AS c
$$) AS (c agtype);
Prefix both queries with EXPLAIN (ANALYZE, BUFFERS) to inspect their plans.
Expected behavior
Both queries should return c = 20000. Since [r:P] already limits r to type P, query B should not need to rebuild each relationship value and check its type again.
Actual behavior
Both queries return c = 20000, but query B is consistently slower. Each independent instance ran 12 alternating comparisons, and query B was slower in all of them:
Independent instance
Query A
Query B
Slowdown
AGE 1.7.0, instance 1
9.43 ms
53.86 ms
5.71x
AGE 1.7.0, instance 2
8.13 ms
52.45 ms
6.45x
The slow plan applies this filter while scanning the P relationship table:
I reproduced this on PostgreSQL 18.6 and opened #2559 as a Draft for design review. The implementation removes only an exact redundant type(r) = <static label> predicate, preserves non-redundant/OR/VLE cases, and avoids mutating the original OPTIONAL MATCH AST. Full AGE regression is 42/42 green; a 12-pair, 20,000-edge benchmark reduced the redundant-query median from 4.622 ms to 2.925 ms (1.620x overhead to 0.996x parity).
Activity
perf(parser): elide redundant edge type filters
linhongyu510 commentedon Sep 1, 2026
I reproduced this on PostgreSQL 18.6 and opened #2559 as a Draft for design review. The implementation removes only an exact redundant
type(r) = <static label>predicate, preserves non-redundant/OR/VLE cases, and avoids mutating the original OPTIONAL MATCH AST. Full AGE regression is 42/42 green; a 12-pair, 20,000-edge benchmark reduced the redundant-query median from 4.622 ms to 2.925 ms (1.620x overhead to 0.996x parity).