【问题标题】:Linq performance for in-memory collection内存收集的 Linq 性能
【发布时间】:2012-06-22 20:50:00
【问题描述】:

我有一个列表:收集用户,其中包含大约 100K+ 用户记录(所有用户对象都从数据库中完全加载,其中包含 Bio、First name、last name 等字段)。此集合在应用程序启动时从数据库中获取并保存在内存中。

然后我有这样的代码:

User cachedUser = users.FirstOrDefault(x => string.Equals(x.UserName, username,
StringComparison.CurrentCultureIgnoreCase));

我用来从这个集合中获取用户。但不知何故,我注意到这个操作非常慢。使用 Linq 查询大对象的内存集合时是否存在性能问题?我是否应该在每次想获得用户时调用数据库?

【问题讨论】:

  • 你明白FirstOrDefault 是O(n),对吧?如果您有一个非常大的集合,则逐个检查每个项目将需要一些时间。 (并且 dbs 通常被索引)有多种方法可以加快速度,其中最重要的是将其放入字典中。你不这样做有什么原因吗?
  • 我想缓存所有认为出于性能原因会更好的用户,因为在我的应用程序的几乎每个页面上都调用了 GetUser() 方法。如果我使用字典,它会更快吗?是字典 O(1) 吗?还是我需要先对字典进行排序?
  • 只需要缓存当前用户吗?您可以使用内置的 SessionCache 对象。
  • @BryanCrosby 不,我想缓存所有用户而不是当前登录的用户。
  • @RockySingh:您是否需要所有用户始终在每个页面上?如果没有,缓存一个子集。如果是的话,要么你的架构出了问题,要么你正在做一些非常时髦的事情:)

标签: c# asp.net performance linq .net-4.0


【解决方案1】:

我认为您可能需要根据您提供给我们的信息重新考虑您的架构。利用数据库,让它为您完成搜索工作。之后观察、测量并做出相应的改变。你可能会意识到你过早地优化了整个事情。

【讨论】:

    【解决方案2】:

    如果您想优化您的响应时间,您可以创建一个Dictionary<T,U> 并在其中搜索用户:

        Dictionary<string, User> usersDictionary = new <Dictionary<string, User>(StringComparer.CurrentCultureIgnoreCase);
    
        // After querying the users from the DB add them to the dictionary             
        usersDictionary.Add(user.UserName, user);
    
        // Then when you need to retrieve a user
        User retrieveUser = null; 
        usersDictionary.TryGetValue(username, out retrieveUser);
    

    希望有帮助!

    【讨论】:

    • 你的意思可能是new Dictionary&lt;string, User&gt;(StringComparer.CurrentCultureIgnoreCase),因为问题需要不区分大小写
    • 我认为将所有用户加载到字典中并不是一个好主意。这需要大量的时间和记忆。此外,您还必须同步访问,以防您更改数据。
    • 据我了解,他无论如何都会加载数据。如果对象的内存占用量低,则不能占用太多时间和太多内存。它就像一个没有网络延迟的内存缓存。这完全取决于最终目标是什么。
    • 而且他没有解释系统应该如何处理更新,所以如果他不介意数据库和内存中可能存在差异,这可能是一个很好的解决方案。这一切都取决于他的真正目标,据我所知,它是让所有用户都在记忆中。在这种情况下,最好的解决方案是使用字典。
    • 他的最后一个问题是他是否应该在每次通话时都调用数据库,我认为是的。这是一个拥有 10 万条记录的用户数据库,我不敢相信它们永远不会改变。如果他想搜索特定城市的所有用户怎么办?您的字典仅在您搜索用户名时才有效。在数据库中,您可以索引多行
    【解决方案3】:

    与任何其他迭代技术(循环、在数组中搜索)一样,您的 LINQ 查询将访问每条记录,直到找到所请求的记录。在最坏的情况下,这意味着 10 万次比较。为了加快速度,您有以下选择:

    1. 使用排序列表或字典:二分查找要快得多。种类 使用 ORDER BY 从数据库中获取数据时的数据
    2. 使用数据集。它就像一个内存数据库,提供更快的搜索
    3. 将数据留在数据库中并设置适当的索引以加快访问速度

    我建议使用数据库,原因如下:

    • 存储 10 万条记录很浪费内存,您可能从不使用这些记录
    • 一旦更改数据,您就必须刷新缓存,这可能相当复杂
    • Web 应用程序是多线程的(每个请求都在自己的线程中运行)。如果您更改数据,则必须与锁同步。
    • 数据库可以缓存频繁调用的数据
    • 您必须编写更少的代码
    • 您有一个可扩展性更好的无状态 Web 应用程序(网络农场)
    • 您的应用程序可能还有其他数据,您无法将所有内容都存储在内存中

    【讨论】:

    • 我的问题是,有这么多记录,即使是数据库访问也很慢。所以我想为什么不在内存中缓存所有用户,因为当用户更新他的个人资料时,我已经使用事件来管理缓存的对象。我们不能以某种方式在内存缓存中索引它吗?
    • 你使用什么样的数据库?在要搜索的行上设置索引时,100k 记录并不多。我永远不会在 Web 应用程序的内存中保留这么多记录。
    • 我们的数据库中的 100K 可能很快就会达到 1M。关键是无论什么 RAM 总是比物理数据文件快。那么,为什么不在使用基于 RAM 的集合而不是依赖 DB 的代码中进行一些高性能算法搜索呢?
    • 因为数据库中的搜索是基于索引的(二进制)而不是顺序的。因为数据库也会将数据缓存在内存中(可能以更有效的方式)。而且因为您可能想要更改数据并且必须对其进行同步。只是不要这样做!如果设计得当,对数据库的访问时间应该是几毫秒。
    • 在内存中缓存 1M 用户是浪费内存,可以更好地利用。即使有 100 万用户,一个优化良好的数据库也应该在几毫秒内检索用户。
    【解决方案4】:

    您注意到的搜索性能的不同是因为数据库使用索引来定位数据库中的字符串,但您在内存中简单地搜索所有记录,直到找到一条。数据库还为字符串保留了一个哈希值,并以更快的速度搜索这个数字哈希,而不是进行实际的字符串比较。

    Dictionary&lt;&gt;也是一个索引,但是添加数据会有延迟,当数据开始增长时,因为当它添加一些数据时,每次都是搜索将它放置在正确的索引点的位置。

    除了数据库缓存结果,许多数据库还缓存索引并创建额外的统计信息,有助于快速定位您要查找的内容。

    最好让数据库进行搜索,除非您可以为额外的自定义案例做出更快的搜索。

    【讨论】:

      猜你喜欢
      • 2010-09-13
      • 1970-01-01
      • 2011-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-29
      • 2017-10-29
      • 2012-07-12
      相关资源
      最近更新 更多