假设我想显示书籍及其作者的列表。在传统的数据库设计中,我会发出一个查询来从Book
表和相关Author
表中检索行,这一步称为eager fetching。这样做是为了避免可怕的N+1 选择问题:如果Author
记录被延迟检索,我的程序将不得不为每个作者发出单独的查询,查询的数量可能与列表中的书籍一样多。
Google App Engine Datastore 是否提供了类似的机制,还是 N+1 选择问题在此平台上不再相关?
假设我想显示书籍及其作者的列表。在传统的数据库设计中,我会发出一个查询来从Book
表和相关Author
表中检索行,这一步称为eager fetching。这样做是为了避免可怕的N+1 选择问题:如果Author
记录被延迟检索,我的程序将不得不为每个作者发出单独的查询,查询的数量可能与列表中的书籍一样多。
Google App Engine Datastore 是否提供了类似的机制,还是 N+1 选择问题在此平台上不再相关?
我认为您是在隐含地询问 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 次
回答你的问题: