C# 如何使用MongoDB作为唯一/枚举存储

C# 如何使用MongoDB作为唯一/枚举存储,c#,mongodb,enumeration,bigdata,C#,Mongodb,Enumeration,Bigdata,这似乎是一个常见的用例。。。但不知何故,我无法让它工作 我试图将MongoDB用作具有唯一项的枚举存储。我创建了一个具有byte[]Id(唯一Id)和时间戳(长,用于枚举)的集合。存储相当大(TB),分布在不同的服务器上。我现在能够从头开始重建商店,因为我仍处于测试阶段 我想做的是两件事: 为我插入的每个项目创建一个唯一的id。这基本上意味着,如果我插入相同的ID两次,MongoDB将检测到这一点并给出一个错误。这种方法似乎很有效 通过其他流程不断枚举存储区中的新项目。我采取的方法是向Inser

这似乎是一个常见的用例。。。但不知何故,我无法让它工作

我试图将MongoDB用作具有唯一项的枚举存储。我创建了一个具有byte[]Id(唯一Id)和时间戳(长,用于枚举)的集合。存储相当大(TB),分布在不同的服务器上。我现在能够从头开始重建商店,因为我仍处于测试阶段

我想做的是两件事:

  • 为我插入的每个项目创建一个唯一的id。这基本上意味着,如果我插入相同的ID两次,MongoDB将检测到这一点并给出一个错误。这种方法似乎很有效
  • 通过其他流程不断枚举存储区中的新项目。我采取的方法是向InsertID添加第二个索引,并在该索引上使用高精度时间戳、服务器id和计数器(只是为了使其唯一且升序)
  • 在最好的情况下,这意味着枚举器将跟踪每个服务器的索引游标。根据我从mongodb查询处理中学到的知识,我预期会出现这种行为。然而,当我尝试执行下面的代码时,似乎要花很长时间才能得到任何东西

            long lastid = 0;
            while (true)
            {
                DateTime first = DateTime.UtcNow;
                foreach (var item in collection.FindAllAs<ContentItem>().OrderBy((a)=>(a.InsertId)).Take(100))
                {
                    lastid = item.InsertId;
                }
                Console.WriteLine("Took {0:0.00} for 100", (DateTime.UtcNow - first).TotalSeconds);
            }
    
    long lastid=0;
    while(true)
    {
    DateTime first=DateTime.UtcNow;
    foreach(collection.FindAllAs()中的var项。OrderBy((a)=>(a.InsertId)).Take(100))
    {
    lastid=item.InsertId;
    }
    WriteLine(“用{0:0.00}表示100”,(DateTime.UtcNow-first).TotalSeconds);
    }
    
    我读过有关游标的文章,但不确定在商店中插入新项目时它们是否满足要求

    正如我所说,我不受任何表结构或类似结构的约束。。。唯一重要的是,随着时间的推移,我可以得到新的项目,而不会得到重复的项目


    -斯蒂芬。

    不知怎的,我弄明白了。。。或多或少

    我手动创建了查询,结果如下:

    find({“InsertId”:{“$gt”:NumberLong(“2020374866209304106”)}).limit(10).sort({“InsertId”:1})

    我在问题中提出的LINQ查询不会生成此查询。在深入研究代码之后,我发现应该是这样的LINQ查询:

    foreach(collection.AsQueryable()中的var项,其中((a)=>(a.InsertId>lastid)).OrderBy((a)=>(a.InsertId)).Take(100))

    AsQueryable()似乎是执行LINQ到MongoDB查询重写的关键

    这给出了结果,但仍然显得很慢(10个结果4秒,100个结果30秒)。但是,当我添加“explain()”时,我注意到查询执行中有“0毫秒”

    我停止了批量插入和tada的过程,它工作正常,而且速度很快。换句话说:我遇到的问题是由于MongoDB的锁定行为,以及我解释linq实现的方式。由于前者是初始批量填充数据存储的结果,这意味着问题已经解决

    关于解决方案的“负面”部分:我更喜欢包含可序列化游标或类似内容的解决方案。。。这个“take”解决方案必须反复迭代b-树。如果有人对此有答案,请告诉我


    -Stefan.

    我不确定是否有你的问题!但是,为什么不让mongodb生成uniqueId呢。它已经做到了!不过,您需要确保一个字符串不会被枚举两次,或者以另一种方式表示两个ID的值不应该相同!听起来像是在使用分片(多台计算机)。你的碎片钥匙是什么?你有多少台服务器?在多个服务器之间通过辅助索引进行查询可能是您的问题,但我需要有关您的配置的更多详细信息。@Ozair:我生成一个唯一的id,因为我使用它进行重复检测。(1) ID基本上是我插入的内容的MD5散列;如果我插入它两次,它将发生冲突并给出一个错误——这是正确的。@GatesVP Yes您是正确的:目前我们对14个MongoDB实例使用切分(将来可能会增加)。切分键是MD5散列。辅助键是插入的ID。换句话说,我确实希望一个枚举查询能够到达14台服务器。但是,对于一个有100个结果的查询来说,20秒太长了;我所期望的行为是,查询进入所有服务器,获取10个结果(你可以很容易地从统计数据中推断出来,因为每台服务器持有的文档数量或多或少相等),合并它们并将它们发送回客户端。1)因为它们总是从一个id开始排序(可能是索引的),然后,除了id和索引中的100项之外,我看不到在哪里“迭代”b树。我不知道怎么才能得到100个……2)你的问题提到了多个读者。用你现在的方式,是什么阻止了两个不同的阅读器处理同一条记录呢?@CraigWilson it没有;我只是为每个“进程”(例如索引等)枚举相同的集合。老实说,我想同时做一些事情,但实际上我在5分钟前刚刚解决了这个难题的一部分:-)MongoDB有一个绝妙的功能,您可以连接到单个副本集并执行查询。如果流程实例的数量与副本集的数量相同,则可以简单地为流程的每个实例枚举一个副本集。事实上,这就是我一直在寻找的完整解决方案。顺便说一句:这个能力对于MongoDB imho来说是一个非常好的USP。@CraigWilson顺便说一句,我并不真正关心100或500或任何批量大小。我更希望MongoDB只给我任何方便的批量大小——这可能是B树中的一个页面。光标就是页面id,'>=x-take-y'只是告诉MongoDB“给我一个光标”