17

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

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

  • 查询集(python 对象)拥有/维护自己的缓存
  • 对数据库的访问是惰性的;即使 queryset.count 是 1000,如果我为 1 条记录执行 object.get,那么对于 1 条记录,dbase 只会被访问一次。
  • 当通过 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 中获取 queryset 对象,该对象将始终以空的本地查询集缓存重新开始;将始终访问 dbase。)

  • 如果上述情况属实,那么我是否应该总是在视图末尾重新保存查询集,在整个视图中使用它来访问一些记录之后,这将导致查询集的本地缓存得到更新,并且应该总是被重新保存到memcached?但是,这总是会导致再次序列化查询集对象。这么多可以加快速度。

  • 或者,cache.set() 是否强制 queryset 对象迭代并从 dbase 访问所有记录,这些记录也会保存在 memcache 中?即使视图只访问查询集的子集,一切都会被保存?

我看到了各个方向的陷阱,这让我认为我
误解了很多事情。

希望这是有道理的,并感谢对一些“标准”指南的澄清或指示。谢谢。

4

1 回答 1

27

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

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

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

更新以回答评论中的问题

您的问题表明您仍然不太了解查询集的工作原理。这一切都与它们何时被评估有关:如果您列出、迭代或切片一个查询集,它会评估它,并且在那时进行数据库调用(我在这里计算迭代下的序列化),并将结果存储在查询集的内部缓存。因此,如果您已经对查询集完成了其中一项操作,然后将其设置为(外部)缓存,则不会导致另一个数据库命中。

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

于 2011-09-30T20:29:11.797 回答