From: Tales da Aparecida Date: Mon, 21 Oct 2024 12:14:03 +0000 (-0300) Subject: models: optimize with_tag_counts using case-when X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=52877f86048b0a9a8f99320ffbe871eae07f95eb;p=thirdparty%2Fpatchwork.git models: optimize with_tag_counts using case-when 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 --- diff --git a/patchwork/models.py b/patchwork/models.py index ae2f4a6d..d5cb31de 100644 --- a/patchwork/models.py +++ b/patchwork/models.py @@ -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):