From 6baf20aaeb695dfcded223575b6ecb987582af15 Mon Sep 17 00:00:00 2001 From: Manuel Raynaud Date: Wed, 9 Sep 2026 15:01:30 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=EF=B8=8F(backend)=20improve=20Documen?= =?UTF-8?q?tViewset.get=5Fqueryset?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The filtering made in the DocumentViewset.get_queryset method is not optimal and lead to a full scan of the Document table. The heavy part is on the filtering on what the user can access between the accesses and the link traces. To have better performance we make an union operation of both document_id list and the filter the id on this list. Postgresql will use the index on the id column. --- src/backend/core/api/viewsets.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index c059eaff1..9e1ac3df3 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -581,22 +581,27 @@ class DocumentViewSet( queryset = queryset.filter(ancestors_deleted_at__isnull=True) # Filter documents to which the current user has access... - access_documents_ids = models.DocumentAccess.objects.filter( - db.Q(user=user) | db.Q(team__in=user.teams) - ).values_list("document_id", flat=True) + access_documents_ids = ( + models.DocumentAccess.objects.filter( + db.Q(user=user) | db.Q(team__in=user.teams) + ) + .order_by() + .values_list("document_id", flat=True) + ) # ...or that were previously accessed and are not restricted - traced_documents_ids = models.LinkTrace.objects.filter(user=user).values_list( - "document_id", flat=True + traced_documents_ids = ( + models.LinkTrace.objects.filter(user=user) + .exclude(document__link_reach=models.LinkReachChoices.RESTRICTED) + .order_by() + .values_list("document_id", flat=True) ) - return queryset.filter( - db.Q(id__in=access_documents_ids) - | ( - db.Q(id__in=traced_documents_ids) - & ~db.Q(link_reach=models.LinkReachChoices.RESTRICTED) - ) - ) + # A single `IN (... UNION ...)` lets PostgreSQL drive the query from the + # (small) set of document ids and probe the primary key index. The + # equivalent `id IN (...) OR (id IN (...) AND ...)` results in a sequential + # scan of the whole document table. + return queryset.filter(id__in=access_documents_ids.union(traced_documents_ids)) def filter_queryset(self, queryset): """Override to apply annotations to generic views."""