Azure cosmosdb 在Cosmos DB中检查数百万个ID

Azure cosmosdb 在Cosmos DB中检查数百万个ID,azure-cosmosdb,azure-cosmosdb-sqlapi,Azure Cosmosdb,Azure Cosmosdb Sqlapi,给定一组可能很大(最多10^7)的ID(以及相关的分区键),我需要验证Cosmos DB集合中是否存在ID在给定集合中的文档 有两种明显的方法可以实现这一点: 使用并行点读取,使用AllowBulkExecution=true,分别检查每个ID/分区密钥对是否存在,并在读取成功返回后立即中止 按分区键将ID分组,对于每个组,发出以下形式的并行查询(使每个查询小于最大查询大小256 kB),并在任何查询返回非空结果时立即中止: 有没有可能在不尝试的情况下说哪一个更快 这里有更多的上下文: 客

给定一组可能很大(最多10^7)的ID(以及相关的分区键),我需要验证Cosmos DB集合中是否存在ID在给定集合中的文档

有两种明显的方法可以实现这一点:

  • 使用并行点读取,使用
    AllowBulkExecution=true
    ,分别检查每个ID/分区密钥对是否存在,并在读取成功返回后立即中止

  • 按分区键将ID分组,对于每个组,发出以下形式的并行查询(使每个查询小于最大查询大小256 kB),并在任何查询返回非空结果时立即中止:

  • 有没有可能在不尝试的情况下说哪一个更快

    这里有更多的上下文:

    • 客户端是一个Azure应用程序服务,与Cosmos DB实例位于同一区域
    • Cosmos DB集合包含约10^7个文档,吞吐量为4000 RU/s
    • ID实际上是长度为36的GUID字符串,因此解决方案2中每个查询的ID数将限制在6500左右,以不超过最大查询大小。换句话说,解决方案2中所需的查询数约为
      n/6500
      ,其中
      n
      是集合中的ID数
    • 不同分区键的数量很小(<10)
    • 文档的平均大小约为500B
    • 默认索引策略
    • 更详细的背景:检查是导入/初始加载操作的一部分。更准确地说,它是导入集验证的一部分,因此可以在写入操作开始之前返回错误。因此,预期的(非错误)情况是集合中没有一个ID已经存在。导入操作预计不会频繁执行(尽管肯定不止一次),因此仅为优化此检查而管理辅助流程/数据不是一个好的折衷方案

      • 我不太清楚我是否理解这一点,但。。。就RU成本而言,查询的成本将超过一个点读取的成本(并且考虑到您的文档大小,这些点读取将花费1RU)

        如果在给定分区内成功地找到特定ID,我看不出您如何能够放弃并行点读取。还要记住,一个ID只在一个分区中是唯一的,所以在多个分区中可以有这个ID

        尝试将给定ID写入给定分区,并查看是否成功(如果发生ID冲突,则失败),可能会更有效


        最后:出于所有实际目的,如果要为保存的每个文档生成新的GUID,则不会有重复的ID。

        谢谢您的回答,但即使点读取只需花费1 RU,也不清楚10^7个点读取是否比10^7/6900=1450个大查询快,这也是典型的延迟。放弃并行查询是可能的,因为并非所有读取/查询都将真正并行运行,因此可以取消它们。尝试写入10^7个ID并立即删除它们是一个解决方案,但我认为它的效率远不如读取/查询。这似乎是一个适合使用change feed为该查询创建专用并行表单的场景。它可能实际上是您自己的索引,可能使用ID的前缀来允许在有限的搜索空间中进行有效的点查询,例如,查看您的ID是否匹配2^16个前缀中的一个,然后如果匹配(不太可能),检查完整ID。我的目标是首先在客户端的内存中完成尽可能多的工作,以减少对Cosmos的需要,只有最便宜的书才读。@NoahStahl有趣的想法。如果集合中包含的项目相对较少,那么这将起作用。在最佳情况下,我们只需要对前缀进行2^16点读取(真负数)。但是在我们的例子中,集合包含的项目超过2^16个(例如,在10^7的顺序中),这些前缀中的大多数都会被使用,因此我们会得到大量的误报,我们会在完整ID上恢复到10^7点读取。我在背景中添加了一些详细信息。如果这种情况不常见,我的直觉是从Cosmos中批量转储所有条目ID,然后加载到内存中的一个巨大哈希集中,以有效地检查是否存在。与向Cosmos发送数百万网络请求的前景相比,这似乎是一个好主意。@NoahStahl这是一个好主意,至少如果集合中的文档数量保持在10^7左右。最有效的“转储”方式可能是查询
        从c
        中选择值c.id,对吗?我可以用这三种方法做一个基准测试,并在这里分享结果。
            SELECT c.id FROM c 
                WHERE c.partitionkey = 'partition123' AND ARRAY_CONTAINS(['id1', 'id2', ...], c.id) 
                LIMIT 1