База данных MySQL слишком часто поражается запросом django - PullRequest
3 голосов
/ 29 декабря 2011

Я использую django-favourites, чтобы получить список объектов, добавленных пользователем.В приложении есть модель и менеджер

class FavoriteManager(models.Manager):
    """ A Manager for Favorites
    """
    def favorites_for_user(self, user):
        """ Returns Favorites for a specific user
        """
        return self.get_query_set().filter(user=user)

class Favorite(models.Model):
    user = models.ForeignKey(User)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

    created_on = models.DateTimeField(auto_now_add=True)

    objects = FavoriteManager()

    class Meta:
        verbose_name = _('favorite')
        verbose_name_plural = _('favorites')
        unique_together = (('user', 'content_type', 'object_id'),)

    def __unicode__(self):
        return "%s added %s as a favorite" % (self.user, self.content_object)

На мой взгляд, я вытаскиваю список избранных для пользователя

 from favorites.models import Favorite
 def myfavorites(request):

      item = Favorite.objects.favorites_for_user(user=request.user)

      return render_to_response('myfavorites.html', {
           'favorites':item
      },
      context_instance=RequestContext(request))

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

{% for fave in favorites %}
    {{ fave.content_type }}<br>
    {{ fave.content_object }}<br><br>
{% endfor %}

Но, используя панель отладки django, я вижу, что дважды обращаюсь к базе данных для каждого цикла.Код запрашивает базу данных для content_type и content_object для каждого предпочтения в объекте избранных.

Как оптимизировать код, чтобы данные извлекались один раз без необходимости нескольких обращений кбаза данных для получения информации?

Ответы [ 2 ]

9 голосов
/ 29 декабря 2011

Вы можете выбрать одно из нескольких решений:

  1. Предварительная выборка общего отношения , вы можете использовать этот фрагмент вот так пример приложения .

  2. Карта идентификаторов / кэширование , используйте тип содержимого и идентификатор объекта, чтобы сделать ключ для кэширования модели, здесь Например, вы можете взять код внутри __getstate__ и __setstate__ и создать тег шаблона, это самое быстрое решение, которое вы можете найти

  3. Извлечение отношений напрямую, в какой-то момент вам, вероятно, понадобится одно из решений, подробно описанных в этой статье о производительности родовых отношений позже при работе с внешними ключами.

  4. Используйте JonhyCache , JohnyCache - это инфраструктура кэширования для наборов запросов, которая работает с абстракцией кэширования django.Я лично еще не пробовал, так как в моих проектах было достаточно трех решений.

  5. Кэшировать фрагмент шаблона , менее хакерский, он выглядит как официальный способ решения этой проблемы , которая порождает множество запросов, и когда пользователь меняет свои избранные, вы можете аннулировать кэшированную версию .

Обратите внимание, что select_related () не работает с общими отношениями .Это связано с тем, что связанный объект может находиться в любой таблице , поэтому невозможно сделать правильные объединения в чистом sql.Родовые отношения - это особенность Django, а не MySQL.

2 голосов
/ 29 декабря 2011

Попробуйте использовать метод запроса select_related .

Нечто подобное должно сработать:

item = Favorite.objects.favorites_for_user(user=request.user).select_related('content_type', 'content_object')

РЕДАКТИРОВАТЬ: jpic правильно указал, что select_related не будет работать для 'content_object', потому что это общий внешний ключ. К сожалению, нет хороших встроенных способов справиться с этим, и не будет, пока Django 1.4 не появится. В то же время, проверьте этот вопрос для некоторых указателей. jpic также опубликовал несколько хороших решений в своем ответе.

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