Skip to content

Commit 681dbe7

Browse files
committed
Add a benchmark to test fetching of many relationships.
This functions as a baseline, to confirm a bug that I believe I spotted which effectively serializes resolution of each relationship.
1 parent e2ace34 commit 681dbe7

File tree

2 files changed

+108
-8
lines changed

2 files changed

+108
-8
lines changed

tests/benchmarks/test_empty_benchmark.py

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
from typing import List
2+
3+
import pytest
4+
import sqlalchemy as sa
5+
import sqlalchemy.orm
6+
import strawberry
7+
import strawberry_sqlalchemy_mapper
8+
from asgiref.sync import async_to_sync
9+
from pytest_codspeed.plugin import BenchmarkFixture
10+
from strawberry.types import Info
11+
12+
13+
@pytest.mark.benchmark
14+
def test_load_many_relationships(
15+
benchmark: BenchmarkFixture, engine, base, sessionmaker
16+
):
17+
class A(base):
18+
__tablename__ = "a"
19+
id = sa.Column(sa.Integer, autoincrement=True, primary_key=True)
20+
21+
class B(base):
22+
__tablename__ = "b"
23+
id = sa.Column(sa.Integer, autoincrement=True, primary_key=True)
24+
25+
class C(base):
26+
__tablename__ = "c"
27+
id = sa.Column(sa.Integer, autoincrement=True, primary_key=True)
28+
29+
class D(base):
30+
__tablename__ = "d"
31+
id = sa.Column(sa.Integer, autoincrement=True, primary_key=True)
32+
33+
class E(base):
34+
__tablename__ = "e"
35+
id = sa.Column(sa.Integer, autoincrement=True, primary_key=True)
36+
37+
class Parent(base):
38+
__tablename__ = "parent"
39+
id = sa.Column(sa.Integer, autoincrement=True, primary_key=True)
40+
a_id = sa.Column(sa.Integer, sa.ForeignKey("a.id"))
41+
b_id = sa.Column(sa.Integer, sa.ForeignKey("b.id"))
42+
c_id = sa.Column(sa.Integer, sa.ForeignKey("c.id"))
43+
d_id = sa.Column(sa.Integer, sa.ForeignKey("d.id"))
44+
e_id = sa.Column(sa.Integer, sa.ForeignKey("e.id"))
45+
a = sa.orm.relationship("A", backref="parents")
46+
b = sa.orm.relationship("B", backref="parents")
47+
c = sa.orm.relationship("C", backref="parents")
48+
d = sa.orm.relationship("D", backref="parents")
49+
e = sa.orm.relationship("E", backref="parents")
50+
51+
mapper = strawberry_sqlalchemy_mapper.StrawberrySQLAlchemyMapper()
52+
53+
@mapper.type(Parent)
54+
class StrawberryParent:
55+
pass
56+
57+
@strawberry.type
58+
class Query:
59+
@strawberry.field
60+
@staticmethod
61+
async def parents(info: Info) -> List[StrawberryParent]:
62+
return info.context["session"].execute(sa.select(Parent)).all()
63+
64+
mapper.finalize()
65+
base.metadata.create_all(engine)
66+
67+
schema = strawberry.Schema(Query)
68+
69+
with sessionmaker() as session:
70+
for _ in range(1000):
71+
session.add(A())
72+
session.add(B())
73+
session.add(C())
74+
session.add(D())
75+
session.add(E())
76+
session.commit()
77+
for i in range(10):
78+
parent = Parent(
79+
a_id=i * 10 + 1,
80+
b_id=i * 10 + 1,
81+
c_id=i * 10 + 2,
82+
d_id=i * 10 + 3,
83+
e_id=i * 10 + 4,
84+
)
85+
session.add(parent)
86+
session.commit()
87+
88+
async def execute():
89+
with sessionmaker() as session:
90+
# Notice how we use a sync session but call Strawberry's async execute.
91+
# This is not an ideal combination, but it's certainly a common one that
92+
# we need to support efficiently.
93+
await schema.execute(
94+
"""
95+
query {
96+
parents {
97+
a { edges { node { id } } },
98+
b { edges { node { id } } },
99+
c { edges { node { id } } },
100+
d { edges { node { id } } },
101+
e { edges { node { id } } },
102+
}
103+
}
104+
""",
105+
context_value={"session": session},
106+
)
107+
108+
benchmark(async_to_sync(execute))

0 commit comments

Comments
 (0)