Fix performance issue in filtering checkin list (Z#23170917) (#4607)

* Fix performance issue in filtering checkin list

* remove test
This commit is contained in:
Raphael Michel
2024-11-06 12:30:37 +01:00
committed by GitHub
parent d8bac7db65
commit 4ca9a43890
3 changed files with 12 additions and 5 deletions

View File

@@ -141,7 +141,7 @@ class CheckinList(LoggedModel):
return self.positions_query(ignore_status=False) return self.positions_query(ignore_status=False)
@scopes_disabled() @scopes_disabled()
def positions_inside_query(self, ignore_status=False, at_time=None): def _filter_positions_inside(self, qs, at_time=None):
if at_time is None: if at_time is None:
c_q = [] c_q = []
else: else:
@@ -149,7 +149,7 @@ class CheckinList(LoggedModel):
if "postgresql" not in settings.DATABASES["default"]["ENGINE"]: if "postgresql" not in settings.DATABASES["default"]["ENGINE"]:
# Use a simple approach that works on all databases # Use a simple approach that works on all databases
qs = self.positions_query(ignore_status=ignore_status).annotate( qs = qs.annotate(
last_entry=Subquery( last_entry=Subquery(
Checkin.objects.filter( Checkin.objects.filter(
*c_q, *c_q,
@@ -202,7 +202,7 @@ class CheckinList(LoggedModel):
.values("position_id", "type", "datetime", "cnt_exists_after") .values("position_id", "type", "datetime", "cnt_exists_after")
.query.sql_with_params() .query.sql_with_params()
) )
return self.positions_query(ignore_status=ignore_status).filter( return qs.filter(
pk__in=RawSQL( pk__in=RawSQL(
f""" f"""
SELECT "position_id" SELECT "position_id"
@@ -214,6 +214,10 @@ class CheckinList(LoggedModel):
) )
) )
@scopes_disabled()
def positions_inside_query(self, ignore_status=False, at_time=None):
return self._filter_positions_inside(self.positions_query(ignore_status=ignore_status), at_time=at_time)
@property @property
def positions_inside(self): def positions_inside(self):
return self.positions_inside_query(None) return self.positions_inside_query(None)

View File

@@ -1967,7 +1967,7 @@ class CheckinListAttendeeFilterForm(FilterForm):
if s == '1': if s == '1':
qs = qs.filter(last_entry__isnull=False) qs = qs.filter(last_entry__isnull=False)
elif s == '2': elif s == '2':
qs = qs.filter(pk__in=self.list.positions_inside.values_list('pk')) qs = self.list._filter_positions_inside(qs)
elif s == '3': elif s == '3':
qs = qs.filter(last_entry__isnull=False).filter( qs = qs.filter(last_entry__isnull=False).filter(
Q(last_exit__isnull=False) & Q(last_exit__gte=F('last_entry')) Q(last_exit__isnull=False) & Q(last_exit__gte=F('last_entry'))

View File

@@ -228,6 +228,7 @@ def checkin_list_env():
# checkin # checkin
Checkin.objects.create(position=op_a1_ticket, datetime=now() + timedelta(minutes=1), list=cl) Checkin.objects.create(position=op_a1_ticket, datetime=now() + timedelta(minutes=1), list=cl)
Checkin.objects.create(position=op_a3_ticket, list=cl) Checkin.objects.create(position=op_a3_ticket, list=cl)
Checkin.objects.create(position=op_a3_ticket, list=cl, type="exit")
return event, user, orga, [item_ticket, item_mascot], [order_pending, order_a1, order_a2, order_a3], \ return event, user, orga, [item_ticket, item_mascot], [order_pending, order_a1, order_a2, order_a3], \
[op_pending_ticket, op_a1_ticket, op_a1_mascot, op_a2_ticket, op_a3_ticket], cl [op_pending_ticket, op_a1_ticket, op_a1_mascot, op_a2_ticket, op_a3_ticket], cl
@@ -260,8 +261,10 @@ def test_checkins_list_ordering(client, checkin_list_env, order_key, expected):
@pytest.mark.django_db @pytest.mark.django_db
@pytest.mark.parametrize("query, expected", [ @pytest.mark.parametrize("query, expected", [
('status=&item=&user=', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']), ('status=&item=&user=', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']),
('status=1&item=&user=', ['A1Ticket', 'A3Ticket']),
('status=0&item=&user=', ['A1Mascot', 'A2Ticket']), ('status=0&item=&user=', ['A1Mascot', 'A2Ticket']),
('status=1&item=&user=', ['A1Ticket', 'A3Ticket']),
('status=2&item=&user=', ['A1Ticket']),
('status=3&item=&user=', ['A3Ticket']),
('status=&item=&user=a3dummy', ['A3Ticket']), # match order email ('status=&item=&user=a3dummy', ['A3Ticket']), # match order email
('status=&item=&user=a3dummy', ['A3Ticket']), # match order email, ('status=&item=&user=a3dummy', ['A3Ticket']), # match order email,
('status=&item=&user=a4', ['A3Ticket']), # match attendee name ('status=&item=&user=a4', ['A3Ticket']), # match attendee name