django querysets + memcached:最佳实践

时间:2011-09-30 19:49:05

标签: python django django-cache

试图了解django低级cache.set()期间发生了什么 特别是,有关查询集的哪个部分存储在memcached中的详细信息。

首先,我是否正确地解释了django文档?

  • 一个queryset(python对象)拥有/维护自己的缓存
  • 对数据库的访问是懒惰的;即使queryset.count是1000, 如果我为一个记录做一个object.get,那么dbase将只是 访问过一次,为1条记录。
  • 每次通过apache prefork MPM访问django视图时 特定的守护进程实例X最终会调用包含某些内容的特定视图 比如“tournres_qset = TournamentResult.objects.all()”, 然后,这将在每个新的tournres_qset对象中生成 被创造。也就是说,任何可能已在内部缓存的内容 通过之前(tcp / ip)访问的tournres_qset python对象, 新请求的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的对象,它总是以新的本地开始 queryset缓存;将始终访问dbase。)

  • 如果以上情况属实,那么我应该只是一直重新保存查询集 在视图的最后,它被用于整个vierw访问 一些记录,这将导致查询集的本地缓存得到更新, 哪个应该总是重新保存到memcached?但是,这总是如此 导致再次序列化queryset对象。 加快速度如此之快。

  • 或者,cache.set()是否强制查询集对象进行迭代和 从dbase访问所有记录,这些记录也将被保存 内存缓存?即使视图只能访问,一切都会被保存 查询集的子集?

我看到各个方向的陷阱,这让我觉得我是 误解了很多东西。

希望这是有道理的,并欣赏澄清或指向某些人 “标准”指南。感谢。

1 个答案:

答案 0 :(得分:24)

查询集是惰性的,这意味着它们在评估之前不会调用数据库。他们可以评估的一种方法是序列化它们,这是幕后的cache.set。所以不,这不是浪费时间:如果你想要的话,你的锦标赛模型的全部内容都将被缓存。它可能不是:如果你进一步过滤查询集,Django将回到数据库,这将使整个事情有点无意义。您应该只缓存实际需要的模型实例。

请注意,初始集中的第三点不太正确,因为这与Apache或preforking无关。它只是一个视图是一个像任何其他函数一样的函数,当函数返回时,函数内局部变量中定义的任何东西都超出了范围。因此,当视图返回响应时,在视图内定义和评估的查询集超出范围,并且在下次调用视图时(即在下一个请求时)将创建新的查询集。无论您以何种方式为Django提供服务都是如此。

但是,这很重要,如果您执行类似将查询集设置为全局(模块级)变量的操作,它将在请求之间保持。 Django服务的大多数方式,这肯定包括mod_wsgi,在回收之前为许多请求保持一个进程处于活动状态,因此查询集的值对于所有这些请求都是相同的。这可以作为一种讨价还价的基础缓存,但很难做到正确,因为你不知道这个过程会持续多长时间,而且其他进程可能并行运行,这些进程有自己的全局变量版本

已更新,可回答评论中的问题

您的问题表明您仍然没有充分了解查询集的工作原理。它是关于何时进行评估的全部内容:如果列出,迭代或切片查询集,则对其进行评估,然后在此时进行数据库调用(我在迭代中计算序列化,此处),并将结果存储在queryset的内部缓存。因此,如果您已经对查询集执行了其中一项操作,然后将其设置为(外部)缓存,则不会导致其他数据库命中。

但是,查询集上的每个filter()操作,即使已经评估过的操作,也是另一个数据库命中。那是因为它是对底层SQL查询的修改,因此Django返回数据库 - 并返回一个 new 查询集,并带有自己的内部缓存。