数据结构的最佳存储,以实现快速查找和持久性

脚本

我有以下方法:

public void AddItemSecurity(int itemId, int[] userIds) public int[] GetValidItemIds(int userId) 

最初我在思考表单上的存储:

 itemId -> userId, userId, userId 

 userId -> itemId, itemId, itemId 

AddItemSecurity基于我如何从第三方API获取数据, GetValidItemIds是我想在运行时使用它的方式。

可能有2000个用户和1000万个项目。 项目ID在表格上:2007123456,2010001234(10位数,前四位代表年份)。

AddItemSecurity不必执行超快速,但GetValidIds需要亚秒。 此外,如果现有的itemId有更新,我需要删除列表中不再存在的用户的itemId。

我正在考虑如何以最佳方式存储它。 最好是在磁盘上(带缓存),但我希望代码可维护和清洁。

如果项目id从0开始,我想为每个用户创建一个长度为MaxItemId / 8的字节数组,如果该项目存在与否则设置一个真/假位。 这将限制每个用户的arrays长度超过1mb,并提供快速查找以及更新每个用户列表的简便方法。 通过使用.Net 4框架将其保存为内存映射文件 ,我认为我也可以获得不错的缓存(如果机器有足够的RAM),而无需自己实现缓存逻辑。 解析id,剥离年份,每年存储一个arrays可能是一个解决方案。

ItemId – > UserId []列表可以直接序列化到磁盘并使用普通的FileStream进行读/写,以便在发生更改时保留列表并进行区分。

每次添加新用户时,所有列表也必须更新,但这可以在每晚完成。

我应该继续尝试这种方法,还是应该探索其他途径? 我认为SQL服务器执行速度不够快,而且会产生开销(至少如果它托管在不同的服务器上),但我的假设可能是错误的。 任何关于此事的想法或见解都表示赞赏。 我想尝试解决它而不添加太多硬件:)

[更新2010-03-31]

我现在已经在以下条件下使用SQL Server 2008进行了测试。

  • 具有两列(userid,itemid)的表都是Int
  • 两列上的聚簇索引
  • 为180个用户添加了约800,000个项目 – 总计1.44亿行
  • 为SQL服务器分配4gb ram
  • 双核2.66ghz笔记本电脑
  • SSD磁盘
  • 使用SqlDataReader将所有itemid读入List
  • 遍历所有用户

如果我运行一个线程,它的平均值为0.2秒。 当我添加第二个线程时,它会上升到0.4秒,这仍然可以。 从那里开始,结果正在减少。 添加第三个线程会带来很多查询,最多可以有2个查询。 第四个线程,最多4秒,第五个线程查询一些查询,最多50秒。

即使在一个线程上,CPU也在进行屋顶处理。 我的测试应用程序需要一些由于快速循环,并sql其余。

这让我得出结论,它不会很好地扩展。 至少不在我测试的硬件上。 有没有办法优化数据库,比如存储每个用户的int数组而不是每个项目一个记录。 但这使得删除项目变得更加困难。

[更新2010-03-31#2]

我使用相同的数据进行了快速测试,将其作为内存映射文件中的位。 它表现得更好。 六个线程产生的访问时间介于0.02s和0.06s之间。 纯粹的记忆束缚。 映射文件由一个进程映射,并由六个其他进程同时访问。 由于sql base占用4GB,磁盘上的文件占用了23mb。

经过大量测试后,我最终使用了内存映射文件,使用稀疏位(NTFS)标记它们,使用NTFS Sparse Files with C#中的代码。

维基百科解释了稀疏文件是什么。

使用稀疏文件的好处是我不必关心我的id所在的范围。如果我只在2006000000和2010999999之间写入id,则该文件将仅从文件中的偏移量250,750,000分配625,000个字节。 到该偏移量的所有空间都在文件系统中未分配。 每个id都存储为文件中的设置位。 被视为位数组的排序。 如果id序列突然改变,那么它将分配在文件的另一部分。

为了检索设置了哪个id,我可以执行OS调用以获取稀疏文件的已分配部分,然后检查这些序列中的每个位。 另外检查特定id是否设置非常快。 如果它落在分配的块之外,则它不在那里,如果它落在其中,它只是一个字节读取和一个位掩码检查以查看是否设置了正确的位。

因此,对于您想要以尽可能快的速度检查的许多id的特定场景,这是我迄今为止找到的最佳方式。

好的部分是内存映射文件也可以与Java共享(结果certificate是必需的)。 Java还支持Windows上的内存映射文件,实现读/写逻辑非常简单。

在你做出决定之前,我真的认为你应该尝试一个不错的数据库。 从长远来看,这样的事情将是一个挑战。 您的用户群实际上非常小。 SQL Server应该能够毫无问题地处理您需要的内容。

2000用户不是太糟糕,但有10万相关项目,你真的应该考虑把它放入数据库。 数据库执行您需要的所有存储,持久性,索引,缓存等,并且它们的性能非常好。

它们还可以在未来实现更好的可扩展性。 如果您突然需要处理200万用户,并且数十亿个具有良好数据库的设置将使扩展成为非问题。