Skip to content

Commit de2c95d

Browse files
narsaynorathandrewshie-sentry
authored andcommitted
fix(ownership-rules): Update email filter to create less conditions (#92539)
Trying to improve the performance of this filter. The current implementation creates an OR condition and calls upper on both the column and the email of the condition for each email passed. This reduces it to a single IN check and a single usage of `upper` to do the case insensitive check. This tries to improve the performance of [this query](https://sentry.sentry.io/explore/traces/trace/9ec6750101a040ed9fcf09d0f3c3c911/?end=2025-05-29T16%3A27%3A49&fov=0%2C88401.99975585938&node=span-862c1dd548d34b56&node=txn-762dfb9f329f4a2d9fe18cdf374762ec&pageEnd=2025-05-29T16%3A27%3A49.000&pageStart=2025-05-29T16%3A25%3A13.000&project=-1&query=trace%3A9ec6750101a040ed9fcf09d0f3c3c911&source=traces&start=2025-05-29T16%3A25%3A13&targetId=bfbc97a674e16357&timestamp=1748535996) (the trace might not point to the correct span, it is the `db` span) by reducing the repeated work of calling `UPPER` in so many conditions. Instead, I've updated the emails filter to annotate the queryset with the uppercased emails, then use the built in `__in` lookup against the emails in an uppercased format. This breaks us away from the `in_iexact` helper that was there before, but that helper is what generates the large condition and there is no clean way to do the lookup with `__in` in a case insensitive way that encapsulates the behaviour as cleanly.
1 parent 1eb7eb6 commit de2c95d

File tree

1 file changed

+7
-1
lines changed
  • src/sentry/users/services/user

1 file changed

+7
-1
lines changed

src/sentry/users/services/user/impl.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from django.db import router, transaction
99
from django.db.models import F, Q, QuerySet
10+
from django.db.models.functions import Upper
1011
from django.utils.text import slugify
1112

1213
from sentry.api.serializers.base import Serializer, serialize
@@ -313,7 +314,12 @@ def apply_filters(self, query: QuerySet[User], filters: UserFilterArgs) -> Query
313314
if "email_verified" in filters:
314315
query = query.filter(emails__is_verified=filters["email_verified"])
315316
if "emails" in filters:
316-
query = query.filter(in_iexact("emails__email", filters["emails"]))
317+
# Since we can have a lot of emails, the in_iexact helper creates too many
318+
# conditions in the query, so we annotate the email and filter by the
319+
# uppercased version of the email for case insensitive search
320+
query = query.annotate(upper_emails=Upper("emails__email")).filter(
321+
upper_emails__in=map(lambda x: x.upper(), filters["emails"])
322+
)
317323
if "query" in filters:
318324
query = query.filter(
319325
Q(emails__email__icontains=filters["query"])

0 commit comments

Comments
 (0)