]> git.ipfire.org Git - thirdparty/patchwork.git/commitdiff
models: optimize with_tag_counts using case-when
authorTales da Aparecida <tales.aparecida@redhat.com>
Mon, 21 Oct 2024 12:14:03 +0000 (09:14 -0300)
committerStephen Finucane <stephen@that.guru>
Wed, 10 Jun 2026 12:44:57 +0000 (13:44 +0100)
Leverage PatchTag index replacing the subquery counter with a JOIN.

The current code is too slow on MySQL, as it doesn't use indexes.
The new approach is more direct and allows proper index usage.

Signed-off-by: Tales da Aparecida <tales.aparecida@redhat.com>
(cherry picked from commit 52877f86048b0a9a8f99320ffbe871eae07f95eb)

patchwork/models.py

index 4e5afc4bae6e8d844d1499256528561a15a8d736..89ac23bc0d1c41bd6c3557f7dae69ef89790ef69 100644 (file)
@@ -5,7 +5,6 @@
 # SPDX-License-Identifier: GPL-2.0-or-later
 
 from collections import Counter
-from collections import OrderedDict
 import datetime
 import random
 import re
@@ -308,8 +307,6 @@ class PatchQuerySet(models.query.QuerySet):
         # Project, and share the project.tags cache between all patch.project
         # references.
         qs = self.prefetch_related('project')
-        select = OrderedDict()
-        select_params = []
 
         # All projects have the same tags, so we're good to go here
         if project:
@@ -317,16 +314,24 @@ class PatchQuerySet(models.query.QuerySet):
         else:
             tags = Tag.objects.all()
 
+        # Annotate the count of each Tag in a column
         for tag in tags:
-            select[tag.attr_name] = (
-                'coalesce('
-                '(SELECT count FROM patchwork_patchtag'
-                ' WHERE patchwork_patchtag.patch_id=patchwork_patch.id'
-                ' AND patchwork_patchtag.tag_id=%s), 0)'
+            qs = qs.annotate(
+                **{
+                    tag.attr_name: models.Sum(
+                        models.Case(
+                            models.When(
+                                patchtag__tag_id=tag.id,
+                                then=models.F('patchtag__count'),
+                            ),
+                            default=models.Value(0),
+                            output_field=models.IntegerField(),
+                        )
+                    )
+                }
             )
-            select_params.append(tag.id)
 
-        return qs.extra(select=select, select_params=select_params)
+        return qs
 
 
 class PatchManager(models.Manager):