perf: 修复 Count 时没有去重的问题

pull/12589/head
Bai 2024-01-18 19:43:55 +08:00 committed by Bryan
parent baa75dc735
commit 6ff852e225
10 changed files with 17 additions and 15 deletions

View File

@ -55,7 +55,7 @@ def clean_historical_accounts():
history_model = Account.history.model history_model = Account.history.model
history_id_mapper = defaultdict(list) history_id_mapper = defaultdict(list)
ids = history_model.objects.values('id').annotate(count=Count('id')) \ ids = history_model.objects.values('id').annotate(count=Count('id', distinct=True)) \
.filter(count__gte=limit).values_list('id', flat=True) .filter(count__gte=limit).values_list('id', flat=True)
if not ids: if not ids:

View File

@ -58,7 +58,7 @@ class DomainListSerializer(DomainSerializer):
@classmethod @classmethod
def setup_eager_loading(cls, queryset): def setup_eager_loading(cls, queryset):
queryset = queryset.annotate( queryset = queryset.annotate(
assets_amount=Count('assets'), assets_amount=Count('assets', distinct=True),
) )
return queryset return queryset

View File

@ -206,7 +206,7 @@ class LabelFilterBackend(filters.BaseFilterBackend):
resources = resources.filter(q) \ resources = resources.filter(q) \
.values('res_id') \ .values('res_id') \
.order_by('res_id') \ .order_by('res_id') \
.annotate(count=Count('res_id')) \ .annotate(count=Count('res_id', distinct=True)) \
.values('res_id', 'count') \ .values('res_id', 'count') \
.filter(count=len(args)) .filter(count=len(args))
return resources return resources

View File

@ -182,14 +182,14 @@ class DatesLoginMetricMixin:
def get_dates_login_times_assets(self): def get_dates_login_times_assets(self):
assets = self.sessions_queryset.values("asset") \ assets = self.sessions_queryset.values("asset") \
.annotate(total=Count("asset")) \ .annotate(total=Count("asset", distinct=True)) \
.annotate(last=Cast(Max("date_start"), output_field=CharField())) \ .annotate(last=Cast(Max("date_start"), output_field=CharField())) \
.order_by("-total") .order_by("-total")
return list(assets[:10]) return list(assets[:10])
def get_dates_login_times_users(self): def get_dates_login_times_users(self):
users = self.sessions_queryset.values("user_id") \ users = self.sessions_queryset.values("user_id") \
.annotate(total=Count("user_id")) \ .annotate(total=Count("user_id", distinct=True)) \
.annotate(user=Max('user')) \ .annotate(user=Max('user')) \
.annotate(last=Cast(Max("date_start"), output_field=CharField())) \ .annotate(last=Cast(Max("date_start"), output_field=CharField())) \
.order_by("-total") .order_by("-total")

View File

@ -34,7 +34,7 @@ class LabelSerializer(BulkOrgResourceModelSerializer):
@classmethod @classmethod
def setup_eager_loading(cls, queryset): def setup_eager_loading(cls, queryset):
""" Perform necessary eager loading of data. """ """ Perform necessary eager loading of data. """
queryset = queryset.annotate(res_count=Count('labeled_resources')) queryset = queryset.annotate(res_count=Count('labeled_resources', distinct=True))
return queryset return queryset

View File

@ -246,6 +246,6 @@ class UsernameHintsAPI(APIView):
.filter(username__icontains=query) \ .filter(username__icontains=query) \
.filter(asset__in=assets) \ .filter(asset__in=assets) \
.values('username') \ .values('username') \
.annotate(total=Count('username')) \ .annotate(total=Count('username', distinct=True)) \
.order_by('total', '-username')[:10] .order_by('total', '-username')[:10]
return Response(data=top_accounts) return Response(data=top_accounts)

View File

@ -198,9 +198,9 @@ class AssetPermissionListSerializer(AssetPermissionSerializer):
"""Perform necessary eager loading of data.""" """Perform necessary eager loading of data."""
queryset = queryset \ queryset = queryset \
.prefetch_related('labels', 'labels__label') \ .prefetch_related('labels', 'labels__label') \
.annotate(users_amount=Count("users"), .annotate(users_amount=Count("users", distinct=True),
user_groups_amount=Count("user_groups"), user_groups_amount=Count("user_groups", distinct=True),
assets_amount=Count("assets"), assets_amount=Count("assets", distinct=True),
nodes_amount=Count("nodes"), nodes_amount=Count("nodes", distinct=True),
) )
return queryset return queryset

View File

@ -80,9 +80,11 @@ class RoleViewSet(JMSModelViewSet):
queryset = Role.objects.filter(id__in=ids).order_by(*self.ordering) queryset = Role.objects.filter(id__in=ids).order_by(*self.ordering)
org_id = current_org.id org_id = current_org.id
q = Q(role__scope=Role.Scope.system) | Q(role__scope=Role.Scope.org, org_id=org_id) q = Q(role__scope=Role.Scope.system) | Q(role__scope=Role.Scope.org, org_id=org_id)
role_bindings = RoleBinding.objects.filter(q).values_list('role_id').annotate(user_count=Count('user_id')) role_bindings = RoleBinding.objects.filter(q).values_list('role_id').annotate(
user_count=Count('user_id', distinct=True)
)
role_user_amount_mapper = {role_id: user_count for role_id, user_count in role_bindings} role_user_amount_mapper = {role_id: user_count for role_id, user_count in role_bindings}
queryset = queryset.annotate(permissions_amount=Count('permissions')) queryset = queryset.annotate(permissions_amount=Count('permissions', distinct=True))
queryset = list(queryset) queryset = list(queryset)
for role in queryset: for role in queryset:
role.users_amount = role_user_amount_mapper.get(role.id, 0) role.users_amount = role_user_amount_mapper.get(role.id, 0)

View File

@ -729,7 +729,7 @@ class JSONFilterMixin:
bindings = RoleBinding.objects.filter(**kwargs, role__in=value) bindings = RoleBinding.objects.filter(**kwargs, role__in=value)
if match == 'm2m_all': if match == 'm2m_all':
user_id = bindings.values('user_id').annotate(count=Count('user_id')) \ user_id = bindings.values('user_id').annotate(count=Count('user_id', distinct=True)) \
.filter(count=len(value)).values_list('user_id', flat=True) .filter(count=len(value)).values_list('user_id', flat=True)
else: else:
user_id = bindings.values_list('user_id', flat=True) user_id = bindings.values_list('user_id', flat=True)

View File

@ -46,7 +46,7 @@ class UserGroupSerializer(ResourceLabelsMixin, BulkOrgResourceModelSerializer):
def setup_eager_loading(cls, queryset): def setup_eager_loading(cls, queryset):
""" Perform necessary eager loading of data. """ """ Perform necessary eager loading of data. """
queryset = queryset.prefetch_related('labels', 'labels__label') \ queryset = queryset.prefetch_related('labels', 'labels__label') \
.annotate(users_amount=Count('users', filter=Q(users__is_service_account=False))) .annotate(users_amount=Count('users', distinct=True, filter=Q(users__is_service_account=False)))
return queryset return queryset