MongoDB数据建模 - 索引和PK

时间:2015-03-10 09:38:50

标签: c# mongodb data-modeling nosql

我目前正在从RDBMS过渡到NoSQL解决方案,更具体地说是MongoDB。考虑我的数据库中的以下表格(原始解决方案要复杂得多,但我包含了这个,所以你有一个想法):

  • 用户(PK_ID_User,FirstName,LastName,...);
  • UserProfile:(PK_ID_UserProfile,ProfileName,FK_ID_User,...);

此表中的键是GUID,但它们是自定义生成的。例如:

  • UserGUID将具有以下结构:US022d717e507f40a6b9551f11ebf2fcb4(所以,US-prefix和随机数), 而UserProfile GUIDS将采用以下格式:UP0025f5804a30483b9b769c5707b02af6(所以UP前缀和随机数)

现在,假设我想将此RDBMS数据模型转换为NoSQL MongoDB。对于我的应用程序(使用C#驱动程序),MongoDB中的所有文档属性都具有相同的名称非常重要。这也是ID字段的计数:名称PK_ID_User和PK_ID_UserProfile,包括GUID,必须相同。

现在,MongoDB使用标准的唯一索引属性_id来存储id。此_id字段的名称不能更改,即使我真的需要我的应用程序来保留列/属性名称。

所以我为我的用户和用户配置文件提出了以下文档结构。请记住,对于这种情况,我选择使用嵌入式引用数据建模,原因有多种,我在此不再解释: 用户文档

{
_id: ObjectId, - indexed
PK_ID_User: custom GUID, - indexed, as it needs to be unique
FirstName: string,
...
}
UserProfile-document
{
_id: ObjectId - indexed
PK_ID_UserProfile: custom GUID, as explained above - indexed, as it needs to be unique,
...
}

这是C#类:

  public class User
  {
    [BsonConstructor]
    public User() { }

    [BsonId] // the _id field
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }

    [BsonElement("PK_ID_User")]
    public string PK_ID_User { get; set; }

    //Other Mapper properties
  }

我选择此建模策略的原因如下:当前项目包括使用ORM和RDBMS的整个Web服务,以及或多或少将数据库对象映射到客户端视图对象的客户端。因此,尽可能保留Ids / PK的名称是非常必要的。我决定让MongoDB在内部使用ObjectId(用于CRUD操作)是最好的,因为它们不会导致性能开销,并且使用自定义GUID,因此它们与我的其余代码兼容。这样,必须进行最小的更改,MongoDB很高兴,我很高兴,因为在外部,我可以根据我的GUID PK查询结果,这些结果将始终是唯一的。 在MongoDB中,我的PK GUID存储为唯一字符串,我想我不必担心服务器端的GUID开销:GUID是由我的C#应用​​程序创建的。

但是,我对性能有疑问,现在每个文档/集合至少有2个索引,并且不知道它在性能方面有多昂贵。

对我的问题有更好的方法,还是我应该坚持现有的解决方案?

亲切的问候。

1 个答案:

答案 0 :(得分:0)

  

我现在每个文档/集合至少有2个索引,并且不知道它在性能方面有多昂贵。

索引会降低插入和更新的性能,并且您没有发布有关写入操作或设置频率的信息。没有测量就无法给出明确的答案。

然后,如果您正在使用网络应用程序,我会说,对您的客户来说,纯粹的网络延迟将比数据之间的差异高几个数量级 ,2或3个索引,因为所有这些操作主要都会打到RAM。

写入磁盘的代价是多少,而不是内存中BTree的重组。当然,拥有越来越多的索引会增加插入的可能性,从而导致必须在磁盘上进行代价高昂的索引树重构,但这也取决于密钥本身的结构。

如果有的话,我担心错误的缓存一致性和GUID的时间局部性:如果你的数据非常时间本地(如日志),那么GUID可能会受到伤害(字符串开头的高抖动) ),因为更新将更有可能重新排列整个子树,典型的时间范围查询将抓住整个树中杂乱的项目。但由于这似乎是关于用户和用户配置文件,这样的查询可能没有多大意义。