django querysets + memcached: лучшие практики

Попытка понять, что происходит во время низкоуровневого cache.set() django. В частности, детали того, какая часть набора запросов хранится в memcached.

Во-первых, правильно ли я интерпретирую документы Django?

  • набор запросов (объект python) имеет / поддерживает свой кеш
  • доступ к базе данных ленивый; даже если queryset.count равен 1000, если я делаю object.get для 1 записи, то база данных будет доступна только один раз для этой 1 записи.
  • при обращении к представлению django через MPA prefork apache, каждый раз, когда конкретный экземпляр X демона в конечном итоге вызывает конкретное представление, которое включает в себя что-то вроде "tournres_qset = TournamentResult.objects.all()", это каждый раз приводит к новому объект tournres_qset создается. То есть все, что могло быть внутренне кэшировано Python-объектом tournres_qset из предыдущего (tcp/ip) посещения, вообще не используется tournres_qset нового запроса.

Теперь вопросы о сохранении вещей в memcached в представлении. Допустим, я добавляю что-то вроде этого вверху представления:

tournres_qset = cache.get('tournres', None)
if tournres_qset is None:
    tournres_qset = TournamentResult.objects.all()
    cache.set('tournres', tournres_qset, timeout)
# now start accessing tournres_qset
# ...

Что хранится во время cache.set()?

  • Весь набор запросов (объект Python) сериализуется и сохраняется?

  • Поскольку набор запросов еще не использовался для получения каких-либо записей, является ли это просто пустой тратой времени, поскольку содержимое отдельных записей фактически не сохраняется в memcache? (Любые будущие запросы будут получать объект набора запросов из memcache, который всегда будет начинаться заново, с пустым локальным кэшем наборов запросов; доступ к базе данных будет всегда.)

  • Если вышеупомянутое верно, то я должен просто всегда повторно сохранять набор запросов в конце представления, после того, как он использовался во всем vierw для доступа к некоторым записям, что приведет к обновлению локального кэша набора запросов, и который должен всегда сохраняются в memcached? Но тогда это всегда приведет к повторной сериализации объекта queryset. Так много для ускорения вещей.

  • Или, заставляет ли cache.set() объект queryset выполнять итерацию и получать доступ из базы данных ко всем записям, которые также будут сохранены в memcache? Все будет сохранено, даже если представление обращается только к подмножеству набора запросов?

Я вижу подводные камни во всех направлениях, что заставляет меня думать, что я
недопонимание целой кучей вещей.

Надеюсь, что это имеет смысл и ценим разъяснения или ссылки на некоторые "стандартные" рекомендации. Благодарю.

1 ответ

Решение

Querysets являются ленивыми, что означает, что они не вызывают базу данных, пока они не оценены. Один из способов, которым они могут быть оценены, - это их сериализация, вот что cache.set делает за кадром. Так что нет, это не пустая трата времени: все содержимое вашей модели Турнира будет кэшировано, если вы этого хотите. Вероятно, это не так: и если вы отфильтруете набор запросов дальше, Django просто вернется в базу данных, что сделает все это немного бессмысленным. Вы должны просто кэшировать экземпляры модели, которые вам действительно нужны.

Обратите внимание, что третий пункт в вашем начальном наборе не совсем правильный, в том смысле, что это не имеет никакого отношения к Apache или предварительному форкингу. Просто представление является функцией, подобной любой другой, и все, что определено в локальной переменной внутри функции, выходит из области видимости, когда эта функция возвращается. Таким образом, набор запросов, определенный и оцененный внутри представления, выходит из области видимости, когда представление возвращает ответ, и новый вызов будет создан при следующем вызове представления, т.е. при следующем запросе. Это тот случай, когда вы служите Джанго.

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

Обновлено, чтобы ответить на вопросы в комментарии

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

Но каждый filter() Операция над набором запросов, даже если он уже оценен, является еще одним попаданием в базу данных. Это потому, что это модификация базового SQL-запроса, поэтому Django возвращается в базу данных и возвращает новый набор запросов со своим собственным внутренним кешем.

Другие вопросы по тегам