查询游标

查询游标可让应用以便捷的批量方式检索查询结果,因此我们建议使用查询游标,而不是使用整数偏移来实现分页功能。如需详细了解如何为应用设计查询结构,请参阅查询

查询游标

查询游标让应用以便捷的批量方式检索查询结果,而且不会因查询偏移而产生开销。执行检索操作后,应用会获得一个游标,该游标是一个不透明的 base64 编码字符串,用于标记上次检索的结果的索引位置。应用可以保存此字符串(例如,保存到 Datastore、Memcache、任务队列的任务载荷中,或者以 HTTP GETPOST 参数形式嵌入网页中),然后可使用游标作为起点来执行后续检索操作,以从上一次检索结束的位置获取下一批结果。检索还可以指定结束游标,以限制所返回的结果集的范围。

偏移与游标

尽管 Datastore 支持整数偏移,但应该尽量避免使用此类偏移。而应该使用游标。使用偏移只能避免将跳过的实体返回给应用,但这些实体仍会在内部被检索。跳过的实体会影响查询的延迟时间,同时由于检索这些实体需要执行读取操作,您的应用会因此而产生费用。使用游标取代偏移可让您省掉所有这些费用。

查询游标示例

在 Python 中,应用会在检索查询结果之后,调用 Query 对象的 cursor() 方法来获取一个游标。如需从游标所在的位置检索其他结果,应用需要使用相同的实体种类、过滤条件和排序顺序准备一个类似的查询,并在执行检索之前将游标传递给查询的 with_cursor() 方法:

from google.appengine.api import memcache
from google.appengine.ext import db

# class Person(db.Model): ...

# Start a query for all Person entities
people = Person.all()

# If the application stored a cursor during a previous request, use it
person_cursor = memcache.get('person_cursor')
if person_cursor:
  people.with_cursor(start_cursor=person_cursor)

# Iterate over the results
for person in people:
  # Do something

# Get updated cursor and store it for next time
person_cursor = people.cursor()
memcache.set('person_cursor', person_cursor)

游标的限制

游标存在如下限制:

  • 游标只能由执行原始查询的同一应用使用,并且只能用于继续执行相同查询。为了在后续检索操作中使用游标,您必须准确地重构原始查询,包括相同的实体种类、祖先实体过滤条件、属性过滤条件以及排序顺序。如果没有设置最初生成游标的同一查询,则无法使用游标检索结果。
  • 由于 !=IN 运算符是使用多个查询实现的,因此使用这些运算符的查询不支持游标。
  • 对于使用不等性过滤条件或排序顺序来处理多值属性的查询,游标并非总能发挥预期的效果。这种多值属性的去重逻辑不会在多次检索之间持续存在,可能导致多次返回相同结果。
  • 新的 App Engine 版本可能会更改内部实现细节,导致依赖于这些细节的游标失效。如果应用尝试使用失效的游标,则 Datastore 会引发 BadRequestError 异常。

游标和数据更新

游标的位置是指结果列表中上次返回的结果之后的位置。游标不是列表中的相对位置(它不是偏移量),而是 Datastore 在开始对结果进行索引扫描时可以跳转到的标记。如果查询的结果在两次使用游标之间发生了变化,则查询只会注意位于游标之后的结果中发生的变化。如果一个新结果出现在查询的游标位置之前,则在获取游标后的结果时不会返回该结果。同样,如果某个不再是查询结果的实体出现在游标之前,则出现在游标后的结果也不会变化。如果从结果集中移除了上次返回的结果,则游标仍会知道如何定位下一个结果。

检索查询结果时,您可以同时使用开始游标和结束游标,以从 Datastore 返回一组连续的结果。使用开始游标和结束游标检索结果时,结果大小不一定会与生成游标时的大小相同。在生成游标与在查询中使用游标这两个时间点之间,可以在 Datastore 中添加实体或者从中删除实体。

后续步骤