2

假设我想显示书籍及其作者的列表。在传统的数据库设计中,我会发出一个查询来从Book表和相关Author表中检索行,这一步称为eager fetching。这样做是为了避免可怕的N+1 选择问题:如果Author记录被延迟检索,我的程序将不得不为每个作者发出单独的查询,查询的数量可能与列表中的书籍一样多。

Google App Engine Datastore 是否提供了类似的机制,还是 N+1 选择问题在此平台上不再相关?

4

1 回答 1

3

我认为您是在隐含地询问 Google App Engine 是否支持 JOIN 以避免N+1 选择问题
Google App Engine 不直接支持 JOIN,但允许您one to many relationship使用ReferenceProperty定义一个。

class Author(db.Model):
  name = db.StringProperty()

class Book(db.Model):
  title = db.StringProperty()
  author= db.ReferenceProperty(Author)

在您的特定场景中,使用两个查询调用,第一个获取作者:

author = Author.all.filter('name =' , 'fooauthor').get()

第二个是查找给定作者的所有书籍:

books = Book.all().filter('author=', author).fetch(...)

您可以获得使用 JOIN 的常见 SQL 查询的相同结果。

例如,当我们想要获得 100 本书时,可能会出现 N+1 问题,每本书都有作者姓名

books = Book.all().fetch(100)
for book in books:
    print book.author.name

在这种情况下,我们需要执行 1+100 次查询,其中 1 次获取书籍列表,100 次取消引用所有作者对象以获取作者姓名(此步骤在book.author.name语句上隐式完成)。

解决此问题的一种常用技术是使用get_value_for_datastore在不取消引用的情况下检索给定书籍的引用作者密钥的方法(即,数据存储获取):

author_key = Book.author.get_value_for_datastore(book)

您可能想阅读有关此主题的精彩博客文章。
此方法从author_key列表开始,从数据存储区预取作者对象,将每个对象设置为正确的实体书。
使用这种方法可以节省大量对数据存储的调用,并且实际上*避免了N+1问题。

* 理论上,在一个书架上,有 100 本书由 100 位不同作者撰写,我们仍然需要调用数据存储区 100+1 次

回答你的问题:

  • Google App Engine 不支持 Eager fetching
  • 有一些技术(不是开箱即用的)有助于避免可怕的N+1 问题
于 2010-11-11T10:36:49.970 回答