]> 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 <stephenfinucane@hotmail.com>
Sun, 7 Jun 2026 15:40:22 +0000 (16:40 +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>
patchwork/models.py

index ae2f4a6dcbaad3f0332c507568ce44ba1c5ae75f..d5cb31de9568f3103d976ca585581bb7ea04c82a 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
@@ -312,8 +311,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:
@@ -321,16 +318,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):