appengine: 缓存引用属性?
我该如何在Google App Engine中缓存一个引用属性呢?
比如说,我有以下这些模型:
class Many(db.Model):
few = db.ReferenceProperty(Few)
class Few(db.Model):
year = db.IntegerProperty()
然后我创建了很多指向同一个Few
的Many
:
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
问题是:
- 每次访问 many.few 都会触发一次数据库查询吗?会的。不确定是一次还是两次调用。
- 如果会的话,有没有办法把结果缓存起来?因为只需要一次查询就能每次都拿到相同的数据。你可以使用 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)
最后,我写了一个库,可以在每次请求时本地缓存实体(不涉及内存缓存)。你可以在这里找到它。不过有个警告:它有单元测试,但使用的人不多,所以可能会有问题。