Как оптимизировать набор запросов из дублированного запроса - PullRequest
0 голосов
/ 15 февраля 2020
1.(0.001) SELECT COUNT(*) FROM (SELECT COUNT(DISTINCT "entities_hero"."id") AS "_hero_count", COUNT(DISTINCT "entities_villain"."id") AS "_villain_count" FROM "entities_origin" LEFT OUTER JOIN "entities_hero" ON ("entities_origin"."id" = "entities_hero"."origin_id") LEFT OUTER JOIN "entities_villain" ON ("entities_origin"."id" = "entities_villain"."origin_id") GROUP BY "entities_origin"."id") subquery; args=()

2.(0.000) SELECT COUNT(*) FROM (SELECT COUNT(DISTINCT "entities_hero"."id") AS "_hero_count", COUNT(DISTINCT "entities_villain"."id") AS "_villain_count" FROM "entities_origin" LEFT OUTER JOIN "entities_hero" ON ("entities_origin"."id" = "entities_hero"."origin_id") LEFT OUTER JOIN "entities_villain" ON ("entities_origin"."id" = "entities_villain"."origin_id") GROUP BY "entities_origin"."id") subquery; args=()


  (0.001) SELECT "entities_origin"."id", "entities_origin"."name", COUNT(DISTINCT "entities_hero"."id") AS "_hero_count", COUNT(DISTINCT "entities_villain"."id") AS "_villain_count" FROM "entities_origin" LEFT OUTER JOIN "entities_hero" ON ("entities_origin"."id" = "entities_hero"."origin_id") LEFT OUTER JOIN "entities_villain" ON ("entities_origin"."id" = "entities_villain"."origin_id") GROUP BY "entities_origin"."id" ORDER BY "entities_origin"."id" DESC; args=()

enter image description here

entity / models.py

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=100)

    class Meta:
        verbose_name_plural = "Categories"

    def __str__(self):
        return self.name

class Origin(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Entity(models.Model):
    GENDER_MALE = "Male"
    GENDER_FEMALE = "Female"
    GENDER_OTHERS = "Others/Unknown"

    choice = (
        (GENDER_MALE, GENDER_MALE),
        (GENDER_FEMALE, GENDER_FEMALE),
        (GENDER_OTHERS, GENDER_OTHERS),
    )

    name = models.CharField(max_length=100)
    alternative_name = models.CharField(max_length=100, null=True, blank=True)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    origin = models.ForeignKey(Origin, on_delete=models.CASCADE)
    gender = models.CharField(max_length=100, choices=choice)
    description = models.TextField()

    def __str__(self):
        return self.name

    class Meta:
        abstract = True

class Hero(Entity):

    class Meta:
        verbose_name_plural = "Heroes"

    is_immortal = models.BooleanField(default=True)
    benevolence_factor = models.PositiveSmallIntegerField(help_text="How benevolent this hero is?")
    arbitrariness_factor = models.PositiveSmallIntegerField(help_text="How arbitrary this hero is?")
    father = models.ForeignKey("self", related_name="+", null=True, blank=True, on_delete=models.SET_NULL)
    mother = models.ForeignKey("self", related_name="+", null=True, blank=True, on_delete=models.SET_NULL)
    spouse = models.ForeignKey("self", related_name="+", null=True, blank=True, on_delete=models.SET_NULL)

class Villain(Entity):
    is_immortal = models.BooleanField(default=False)
    malevolence_factor = models.PositiveSmallIntegerField(help_text="How malevolent this villain is?")
    power_factor = models.PositiveSmallIntegerField(help_text="How powerful this villain is?")
    is_unique = models.BooleanField(default=True)
    count = models.PositiveSmallIntegerField(default=1)

entity / admin.py

@admin.register(Origin)
class OriginAdmin(admin.ModelAdmin):

    list_display = ("name","hero_count", "villain_count")

    def get_queryset(self, request):
        queryset = self.model.objects.all().annotate(
            _hero_count=Count("hero", distinct=True),
            _villain_count=Count("villain", distinct=True),
        )
        return queryset

    def hero_count(self, obj):
        return obj._hero_count

    def villain_count(self, obj):
        return obj._villain_count

1 Ответ

2 голосов
/ 19 февраля 2020

Django Администратор запускает запрос count (*) дважды на странице списка.

  1. Чтобы получить количество объектов. Django Администратор отображает количество объектов на странице списка. Это можно отключить, установив show_full_result_count = False как , упомянутое в документах .

  2. Django нумерация страниц. Django paginator выполняет подсчет (*) для генерации нумерации страниц. Для больших таблиц выполнение этого запроса каждый раз замедляет загрузку страницы. Быстрое решение состоит в том, чтобы кэшировать счетчик в paginator и использовать повторно. При этом первая загрузка страницы будет медленнее, но последующие страницы будут загружаться быстрее. Вот фрагмент кода для django кэшированного пагинатора .

...