【问题标题】:How does Cosmos DB Continuation Token work?Cosmos DB 延续令牌如何工作?
【发布时间】:2020-08-17 19:56:36
【问题描述】:

乍一看,延续令牌在 Cosmos DB 中的作用很明显:将其附加到下一个查询会为您提供下一组结果。但是“下一组结果”究竟是什么意思呢?

意思是:

  1. 下一组结果是否好像在第一次查询时已完全执行原始查询而没有分页(跳过适当数量的文档)?
  2. 下一组结果是否与现在已执行原始查询一样(跳过适当数量的文档)?
  3. 完全不同的东西?

答案 1. 似乎更可取,但不太可能,因为服务器需要存储无限量的状态。但是答案 2. 也有问题,因为它可能会导致不一致,例如如果页面查询之间的基础数据发生了变化,则同一文档可能会跨页面多次提供。

【问题讨论】:

    标签: azure-cosmosdb


    【解决方案1】:

    Cosmos DB 查询执行在服务器端是无状态的。延续令牌用于重新创建索引的状态并跟踪执行进度。

    “下一组结果”的意思是,从前一次执行的“书签”再次执行查询。此书签由延续令牌提供。

    1. 在延续期间创建的文档

    根据执行插入和查询的位置,它们可能返回也可能不返回。

    示例:

    SELECT * FROM c ORDER BY c.someValue ASC

    假设书签的 someValue = 10,查询引擎使用 someValue = 10 的延续令牌继续处理。

    如果您要在两次查询之间插入一个 someValue = 5 的新文档,它不会在下一组结果中显示

    如果新文档插入到“页面”即>书签中,它将显示在下一组结果中

    1. 在继续过程中更新文档

    与上述相同的逻辑也适用于更新 (见#4)

    1. 在继续过程中删除的文档

    它们不会出现在下一组结果中。

    1. 重复的机会

    如果是以下查询,

    SELECT * FROM c ORDER BY c.remainingInventory ASC

    如果在第一组结果之后更新了剩余库存并且现在满足第二页的 ORDER BY 条件,则文档将再次显示


    Cosmos DB 不提供跨查询页面的快照隔离。 然而,根据产品团队的说法,这是一种非常罕见的情况,因为对延续的查询非常快,并且在大多数情况下,所有查询结果都会在第一页返回。

    【讨论】:

    • 谢谢,知道不包括新项目已经很有帮助,因此可以排除上面的选项#2。但它仍然不是“下一组结果”的完整规范。显然,延续令牌中编码的信息不足以重新创建整个索引(否则它可能会增长到与整个集合一样大),并且服务器端没有存储任何状态,因此丢失了一些信息,选项 #1 不可行.间歇性删除是否可以观察到?间歇性更新?
    • 我无法确认您的说法,即在第一页之后创建的项目不包含在后续页面中。我使用 Sacha Bruttin 的 Cosmos DB Explorer 查询所有页面大小为 1 的文档(未设置 ResponseContinuationTokenLimitInKb),并通过逐页检索,最终观察到在单页请求之间创建的所有文档。此外,页面请求之间的删除和更新始终可以在后续页面上观察到。这表明选项 #2 是正确的。
    • 延续令牌用于构造索引的整个状态。这就是为什么令牌可以增长超过 12K 并且正如您正确指出的那样,在某些情况下大于文档本身。某些客户端对 http 标头中接收到的令牌的长度(大小)有限制。所以引入了 ResponseContinuationTokenLimitInKb 的选项。通过限制令牌大小,您仍然可以与 Cosmos 对话,但由于它没有序列化状态所需的所有数据,它现在需要再次扫描索引,因此还会返回新的添加、删除和更改的数据。
    • 我已经有一段时间致力于处理延续令牌的问题,让我对此进行更多研究并在此处更新我的发现。我也会使用 Cosmos DB Explorer。
    • 谢谢,那真的很有帮助。澄清一下:在我的实验中,令牌大小不受 ResponseContinuationTokenLimitInKb 的限制,但所有中间写入(创建、更新、删除)都可以在后续页面上观察到。
    【解决方案2】:

    根据初步实验,答案似乎是选项 #2,或更准确地说:

    1. 在提供第一页后创建的文档可在后续页面上观察到
    2. 在提供第一页后更新的文档可在后续页面上观察到
    3. 在提供第一页后删除的文档在后续页面中被省略
    4. 文档永远不会送达两次

    上面的第一个陈述与 MSFT 的信息相矛盾(cf. Kalyan 的回答)。如果能从 Cosmos DB 团队获得更合格的答案,准确指定检索页面的语义,那就太好了。这对于在 UI 中显示数据可能不是很重要,但对于后端的数据处理可能是必不可少的,因为在执行查询时似乎没有任何方式禁用分页 ( cf. Are transactional queries possible in Cosmos DB?)。


    实验方法

    我使用 Sacha Bruttin 的 Cosmos DB Explorer 查询包含 5 个文档的集合,因为该工具允许使用页面大小和其他请求选项。

    页面大小设置为 1,并且启用了跨分区查询。尝试了不同的查询,例如SELECT * FROM cSELECT * FROM c ORDER BY c.name

    在检索到第 1 页后,插入了新文档,并更新和删除了一些现有文档(包括应该出现在后续页面上的文档)。然后依次检索所有后续页面。

    (快速查看该工具的源代码确认未设置ResponseContinuationTokenLimitInKb。)

    【讨论】:

    • 我确信我曾经遇到过新文件没有被退回的问题。在这里发现一个这样的问题,与 stackoverflow.com/questions/54216251/… 讨论相同的问题@让我尝试与 Cosmos 团队的某个人取得联系并确认这一点
    • 对于禁用分页的评论,您可以将 FeedOptions 中的 MaxItemCount 属性设置为较大的数字(最多 1000 个)以获得每页更多的结果
    • 您可以设置 MaxItemCount 以获得更大的页面,但关键是您不能使用它来完全避免分页,因此似乎没有办法在事务中进行查询方式。
    猜你喜欢
    • 1970-01-01
    • 2021-11-02
    • 1970-01-01
    • 1970-01-01
    • 2019-02-08
    • 2019-09-17
    • 1970-01-01
    • 1970-01-01
    • 2020-10-14
    相关资源
    最近更新 更多