【问题标题】:Datatype suggestions for storage of a "lot" of strings?存储“大量”字符串的数据类型建议?
【发布时间】:2012-11-23 08:52:15
【问题描述】:

我有一个非常定期查询数据库的应用程序。它返回多达数百万个字符串,其中绝大多数是 bieng 重复。我需要将所有这些记录存储在内存中,并尝试将占用空间最小化。

我目前的设计是在每个字符串上调用 GetHashCode(),然后存储哈希而不是字符串本身。

然后我尝试将其添加到Dictionary<hashcode,string>() 结构中。我还保留了第二个 Dictionary<hashcode,count>() 字典,随着更多条目使用该字符串,它会递增\递减。

在条目处理方法中,我递减计数器,如果使用量降至零,则从字典中删除字符串。

所以,有几个问题:

这是愚蠢的差事吗?与与这个巨头合作相比,我可以使用哪些数据类型可以节省大量时间\精力?

我希望我的字符串表是线程安全的(目前不是)。使用 ConcurrentDictinary 是我的最佳选择吗?

提前致谢。

【问题讨论】:

    标签: c# .net hash dictionary storage


    【解决方案1】:

    我看不出获取哈希码并将字符串存储在Dictionary<hash,string> 中以及将计数存储在单独的字典中的意义。您可以使用字符串本身作为键,字典将自动(内部)创建和存储哈希码。因此,仅使用一本字典 Dictionary<string,count> 就足够了。您还可以通过dict.Keys从字典中检索字符串。

    两个不同字符串的哈希码可以相同。这称为碰撞。 Dictionary<TKey,TValue> 会自动处理这些冲突。

    ConcurrentDictinary<TKey,TValue> 似乎是合适的;但是,我对此没有任何经验。

    【讨论】:

      【解决方案2】:

      这样做的主要问题是两个不同的字符串可以具有相同的哈希码。

      听起来你让这变得比它需要的更复杂。你需要的是实习:

      http://msdn.microsoft.com/en-us/library/system.string.intern.aspx

      CLR 已经维护了一个字符串实例表以节省内存。

      更新

      但是...您应该牢记文档中的警告:在 CLR 卸载之前,不会对实习字符串进行垃圾收集,即它们会在您的应用程序域的生命周期内一直存在。

      但是您可以很容易地自己实现相同的模式:

      class LocalStringInterner
      {
          private Dictionary<string, string> _strings = new Dictionary<string, string>();
      
          public string Intern(string str)
          {
              string interned;
              if (_strings.TryGetValue(str, out interned))
                  return interned;
      
              _strings.Add(str, str);
              return str;
          }
      }
      

      这样,当你不再需要那组字符串时,你可以放弃LocalStringInterner

      为了安全地从多个线程中使用,您可以将Intern 的主体包裹在lock(_strings) 中。

      【讨论】:

      • 是的,我意识到了这种可能性,尽管通过编写我自己的 GetHashCode() 函数“更多保证”该函数是正确唯一的,这很容易解决。
      • 我很想看看它的代码。为了缩小存储的数据使其小于原始字符串,那么您必须丢弃一些信息。如果你扔掉的东西就是差异发生的地方怎么办?
      • 我没有写出我所有的实现,但它会做以下事情:当我存储字符串时,我会得到哈希码,如果字符串与给定的哈希码不匹配,然后我将使用我的辅助哈希。如果这仍然不起作用,我会接受那个骗子的,我必须想办法。我想哈希码现在不是我关心的问题,而是整个数据结构。
      • 这是出乎意料的,它看起来很有希望。我将对此进行研究,然后可能会将其标记为已回答。
      【解决方案3】:

      也许 md5-Hash 可以帮助您。它应该(理论上)是唯一的,并且受到大多数数据库的支持(如果不是 C# 将帮助您)。

      MySQL:

      SELECT name, md5(name)
      FROM user
      

      也就是说,我会考虑一种更好的数据库方法。

      如果您在服务器端的每个字符串都有一个唯一的 id,这应该是一件容易的事。

      假设您有一个名为 string_resources 的表,其中包含一个 auto_increment id 列和一个 varchar 字段。我还会在 value 上添加一个唯一索引,以确保您不会两次存储字符串。

      |id     | value          |
      |1      | Hello          |
      |2      | World          |
      ...
      |145789 | Something else |
      

      现在您可以将 int 值存储在字典中

      md5: 128bit
      int32: 32bit  // <-- You Don't Say?
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-09-12
        • 2020-03-03
        • 2010-10-08
        • 2015-02-08
        • 2018-07-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多