Как сделать запрос в Django с максимальной эффективностью? - PullRequest
0 голосов
/ 11 июня 2019

Недавно я обнаружил, что слишком много проблем с оптимизацией SQL-запросов.django-debug-tool сообщил о сотнях похожих и повторяющихся запросов.Итак, я пытаюсь выяснить наилучшую эффективность Django ORM, чтобы избежать ненужной оценки набора запросов.

Как видно из приведенной ниже модели хранилища, модель хранилища имеет много внешнего ключа и множество полей ManyToManyFields.Из-за этой структуры существует множество фрагментов кода, которые наносят удар по файлам шаблонов HTML, таким как store.image_set.all или store.top_keywords.all.Все начинается с store. На каждой странице сведений о магазине я просто передаю кешированный объект магазина с помощью prefetch_related или select_related.Это плохой подход?Должен ли я кэшировать и prefetch_related или select_related каждый внешний ключ или ManyToManyField отдельно на views.py?

HTML-шаблоны

{% for img in store.image_set.all %}
  {{ img }}
{% endfor %}
{% for top_keyword in store.top_keywords.all %}
  {{ top_keyword }}
{% endfor %}
{% for sub_keyword in store.sub_keywords.all %}
  {{ sub_keyword }}
{% endfor %}

views.py

class StoreDetailView(View):

    def get(self, request, *args, **kwargs):

        cache_name_store = 'store-{0}'.format(store_domainKey)
        store = cache.get(cache_name_store, None)
        if not store:
            # query = get_object_or_404(Store, domainKey=store_domainKey)
            query = Store.objects.all().prefetch_related('image_set').get(domainKey=store_domainKey)
            cache.set(cache_name_store, query)
            store = cache.get(cache_name_store)

        context = {
            'store': store,
        }
        return render(request, template, context)

models.py

class Store(TimeStampedModel):

    categories = models.ManyToManyField(Category, blank=True)
    price_range = models.ManyToManyField(Price, blank=True)

    businessName = models.CharField(unique=True, max_length=40,
                                    verbose_name='Business Name')

    origin = models.ForeignKey(Origin, null=True, on_delete=models.CASCADE, blank=True)
    ship_to = models.ManyToManyField(ShipTo, blank=True)

    top_keywords = models.ManyToManyField(Keyword, blank=True, related_name='store_top_keywords')
    sub_keywords = models.ManyToManyField(SubKeyword, blank=True, related_name='store_sub_keywords')

    sponsored_stores = models.ManyToManyField(
        'self', through='Sponsorship', symmetrical=False, related_name='sponsored_store_of_store')
    similar_stores = models.ManyToManyField(
        'self', through='Similarity', symmetrical=False, related_name='similar_store_of_store')


    shortDesc = models.TextField(blank=True, verbose_name='Short Description')
    longDesc = models.TextField(blank=True, verbose_name='Long Description')

    returnPol = models.TextField(verbose_name='Return Policy', blank=True)
    returnUrl = models.CharField(max_length=255, null=True, blank=True, verbose_name='Return Policy URL')

    likes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, editable=False)

    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, editable=False, on_delete=models.CASCADE,
                                   related_name='stores_of_created_by', null=True, blank=True)
    updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, editable=False, on_delete=models.CASCADE,
                                   related_name='stores_of_updated_by', null=True, blank=True)

1 Ответ

1 голос
/ 11 июня 2019

Я бы действительно не советовал настраивать кэширование / оптимизацию производительности, если только это не последнее средство. У Django есть отличные документы по комплектам запросов и по оптимизации - если вы будете следовать им, у вас не должно возникнуть серьезных проблем с производительностью, требующих пользовательских обходных путей.

Я думаю проблема здесь в том, что вы печатаете свои объекты в шаблоне и, следовательно, вызываете их метод str(). В этом нет ничего плохого, но я бы проверил, какие переменные вы используете в своих str() методах. Я подозреваю, что вы ссылаетесь на другие модели? То есть str() метод в вашей модели изображения (или что-то еще) делает что-то вроде image.field.other_field. В этом случае ваш запрос должен выглядеть так:

queryset = Store.objects.prefetch_related('image_set__field')

Ваш окончательный набор запросов может выглядеть следующим образом:

queryset = Store.objects.prefetch_related('image_set__field1', 'image_set__field2', 'top_keywords__field3', ...)

Обратите внимание, что вы все равно можете передать это в get_object_or_404 примерно так:

get_object_or_404(queryset, pk=<your_stores_id>)

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...