appengine: 缓存引用属性?

3 投票
2 回答
1612 浏览
提问于 2025-04-15 13:07

我该如何在Google App Engine中缓存一个引用属性呢?

比如说,我有以下这些模型:

class Many(db.Model):
    few = db.ReferenceProperty(Few) 

class Few(db.Model):
    year = db.IntegerProperty()

然后我创建了很多指向同一个FewMany

one_few = Few.get_or_insert(year=2009)
Many.get_or_insert(few=one_few)
Many.get_or_insert(few=one_few)
Many.get_or_insert(few=one_few)
Many.get_or_insert(few=one_few)
Many.get_or_insert(few=one_few)
Many.get_or_insert(few=one_few)

现在,如果我想遍历所有的Many,读取它们的few值,我会这样做:

for many in Many.all().fetch(1000):
  print "%s" % many.few.year

问题是:

  • 每次访问many.few时,是否都会触发一次数据库查询?
  • 如果是这样,有没有办法缓存一下,因为只需要查一次就能每次都得到同样的实体?

正如某个评论中提到的:我知道有memcache,但我不太确定在通过引用调用其他实体时,如何“注入”它。

无论如何,memcache也没什么用,因为我需要的是在一次执行中进行缓存,而不是在不同执行之间。使用memcache并不能优化这个调用。

2 个回答

1

问题是:

  1. 每次访问 many.few 都会触发一次数据库查询吗?会的。不确定是一次还是两次调用。
  2. 如果会的话,有没有办法把结果缓存起来?因为只需要一次查询就能每次都拿到相同的数据。你可以使用 memcache 来实现这个功能。这个功能在 google.appengine.api.memcache 这个包里。

关于 memcache 的详细信息可以查看 http://code.google.com/appengine/docs/python/memcache/usingmemcache.html

8

第一次你访问任何引用属性时,系统会去获取这个实体——即使你之前已经获取过与其他引用属性关联的同一个实体。这会涉及到一次数据存储的获取操作,虽然这比查询要便宜,但如果可以的话,还是尽量避免。

有一个很不错的模块可以无缝地缓存实体,你可以在这里找到。它在数据存储的更低层次工作,会缓存所有的数据获取操作,而不仅仅是引用属性的访问。

如果你想一次性解决多个引用属性,还有另一种方法:你可以先获取所有的键,然后一次性获取这些实体,像这样:

keys = [MyModel.ref.get_value_for_datastore(x) for x in referers]
referees = db.get(keys)

最后,我写了一个库,可以在每次请求时本地缓存实体(不涉及内存缓存)。你可以在这里找到它。不过有个警告:它有单元测试,但使用的人不多,所以可能会有问题。

撰写回答