假设我要显示一系列书籍及其作者。在传统的数据库设计中,我会发出一个查询来检索Book
表中的行以及相关的Author
表,这一步称为 eager fetching 。这样做是为了避免可怕的 N + 1选择问题:如果懒惰地检索Author
记录,我的程序将不得不为每个作者发出一个单独的查询,可能与列表中有书籍。
Google App Engine数据存储区是否提供了类似的机制,或N + 1选择问题是否与此平台不再相关?
答案 0 :(得分:3)
我认为您隐含地询问Google App Engine是否支持JOIN以避免 N + 1选择问题。
Google App Engine不直接支持JOIN,但允许您使用ReferenceProperty定义one to many relationship
。
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查询的相同结果。
N + 1 问题可能会在我们想要获得100本书时出现,每本书都有作者姓名:
books = Book.all().fetch(100)
for book in books:
print book.author.name
在这种情况下,我们需要执行1 + 100个查询,一个用于获取书籍列表,100个用于取消引用所有作者对象以获取作者姓名(此步骤在book.author.name
语句中隐式完成)。
解决此问题的一种常用技巧是使用get_value_for_datastore
方法检索给定书籍的引用作者的密钥而不解除引用(即数据存储区提取):
author_key = Book.author.get_value_for_datastore(book)
您可能希望阅读有关此主题的精彩blog post
此方法从author_key
列表开始,从数据存储区中将作者对象预设为每个正确的实体书。
使用这种方法可以节省大量数据存储区调用,实际上 * 可以避免 N + 1 问题。
*理论上,在100个不同作者编写的100本书的书架上,我们仍然需要将数据库调用100 + 1次
回答你的问题: