Skip to content

Commit 084550f

Browse files
committed
fix(statistics): use subquery instead of join to avoid cartesian product
The way we filter in the statistics view, any added filter (that affects reports) adds a "dimension" to the cartesian product, exploding the total number of hours reported. Instead of using JOIN, we do EXISTS(SUBQUERY) now, which should avoid this issue. Might be a tiny bit slower, but let's try to make it correct first, then fast.
1 parent 181db3f commit 084550f

File tree

1 file changed

+7
-2
lines changed

1 file changed

+7
-2
lines changed

backend/timed/reports/views.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from zipfile import ZipFile
99

1010
from django.conf import settings
11-
from django.db.models import F, Q, QuerySet, Sum
11+
from django.db.models import F, Q, Exists, OuterRef, QuerySet, Sum
1212
from django.db.models.functions import ExtractMonth, ExtractYear
1313
from django.http import HttpResponse
1414
from django.utils.http import content_disposition_header
@@ -117,9 +117,14 @@ def filter(self, /, **kwargs):
117117
return new_qs
118118

119119
def filter_base(self, *args, **kwargs):
120+
filtered = (
121+
self.model.objects.filter(*args, **kwargs)
122+
.values("pk")
123+
.filter(pk=OuterRef("pk"))
124+
)
120125
return StatisticQueryset(
121126
model=self.model,
122-
base_qs=self._base.filter(*args, **kwargs),
127+
base_qs=self._base.filter(Exists(filtered)),
123128
catch_prefixes=self._catch_prefixes,
124129
agg_filters=self._agg_filters,
125130
)

0 commit comments

Comments
 (0)