【问题标题】:.NET .ToList function is WAY WAY too slow.NET .ToList 函数太慢了
【发布时间】:2011-04-15 17:51:11
【问题描述】:

我们在使用 .ToList 命令时遇到了很多麻烦,它在 VB.NET 中与 MVC ASP.NET Web 项目一起使用。

我们的数据库中有大约 2000 个条目,我们使用 LINQ 命令对 2000 个条目进行选择和排序。 .ToList 方法将结果转换为我们的寻呼机和网格构建器的列表。问题是,.ToList 需要 WAY WAY TOO 长(我们说要执行 40-60 秒),所以我们的网站看起来慢得要命。

我们在数据库上测试了等效的 SQL 命令,它响应迅速。这不是命令或慢速数据库服务器的问题。我们尝试了一个 IEnumrable 女巫,它的速度要快得多,但我们的网格最后需要 .ToList 格式的它。 .ToList 有什么问题?有什么我们可以做的吗?

代码如下:

 'list = (From c In _entities.XXXXXXXXSet.Include("XXXXXX").Include("XXXXXX") _
                Where Not (c.XXXXXX Is Nothing AndAlso c.XXXXXX = String.Empty) _
                And c.XXXXXX = codeClient _
                And c.XXXXXX > dateLimite _
                Order By c.XXXXXX Descending _
                Select c).ToList()

我们划分了代码,只留下了 .ToList 函数,而这确实是一直很糟糕的地方。 LINQ 命令立即执行。

非常感谢。 汤姆

【问题讨论】:

  • 听起来像是分页/网格工作在导致问题的 .ToList() 调用之后。
  • LINQ 命令不会立即“执行” - 表达式不会被执行,直到 .ToList 导致它被枚举...
  • @Joel:不,我进入了函数,而 .ToList 行实际上需要 30-40 秒才能执行。
  • 当您说“等效的 SQL 命令”时,您实际上得到了 LINQ 查询产生的 SQL SELECT,还是您认为的那样?通常,它们几乎不是一回事。
  • 查询不会执行,直到你做一些事情来枚举它。 (在这种情况下,调用 ToList() 会枚举它,这就是执行查询的原因)。如果您拆分对 ToList 的调用并连接 SQL Profiler,您可以观察该行为——您将看到查询实际上并没有转到 SQL Server,直到您执行 ToList() 命令(您也可以消除 ToList( ) 调用,然后在列表上运行 foreach —— 你会得到同样的效果,在你迭代之前查询不会真正执行)。

标签: sql vb.net linq linq-to-sql entities


【解决方案1】:

当然,LINQ 命令很快就会“执行”,因为它只是代表查询。只有在您对其进行迭代时才会执行查询,这正是 ToList 方法所做的。

我建议您在寻呼机中使用Skip 和Take 运算符来缩小从数据库查询的结果范围。这样做,您只需请求 10 或 20 个元素或任何您需要的元素,从而获得更流畅的体验。

【讨论】:

    【解决方案2】:

    我认为使用Skip 和Take 在查询中分页而不是一次性获取所有数据会更好。

    list = (From c In _entities.XXXXXXXXSet.Include("XXXXXX").Include("XXXXXX") _
                Where Not (c.XXXXXX Is Nothing AndAlso c.XXXXXX = String.Empty) _
                And c.XXXXXX = codeClient _
                And c.XXXXXX > dateLimite _
                Order By c.XXXXXX Descending _
                Select c).Skip(pageSize * pageIndex).Take(pageSize).ToList();
    

    加上一些针对性强的缓存(如果可能的话)应该可以提供更快速的用户体验。

    【讨论】:

    • 2000 行确实不足以强制分页。我通常会在 0.05 秒内拉出 2000 行。
    • @David:这在很大程度上取决于相关查询。无论如何,我认为在用户面前打 2000 行总是一个坏主意。鉴于此,我认为最好不要每次都从数据库中获取所有 2000 行,而只是过滤掉少数实际使用的行。
    • 我们用这种方法编码,从 30-40 秒缩短到 1-3 秒!非常感谢
    【解决方案3】:

    当您说“数据库上的等效 SQL 命令并且它快速响应”时 - 是 LINQ 代码正在生成的实际 SQL 语句还是逻辑上等效的手动编码 SQL?

    因为 LINQ 生成的代码可能效率不高。

    【讨论】:

    【解决方案4】:

    对于这样的事情,在分析器中运行代码通常很有用。可能有很多事情会变慢...网络、内存、对象大小等。

    您还可以创建自己的列表并将 IEnumerable 值复制到其中。如果可能的话,我建议您更改网格以接受 IEnumerable。

    【讨论】:

      【解决方案5】:

      要确认 ToList 相对于查询执行的性能,请添加一条语句并进行比较:

        //this call iterates a query, causing a database roundtrip.
      List<Row> result = query.ToList();
        //this call generates a new List by iterating the old List.
      result = result.ToList();
      

      查看您的查询,我怀疑您需要一个 codeClient,以及对.Include 的调用中提到的每个表的索引。抓取生成的sql,查看执行计划确认。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-11
        • 1970-01-01
        • 2021-08-25
        • 1970-01-01
        • 1970-01-01
        • 2013-11-13
        • 2013-03-10
        • 2014-06-07
        相关资源
        最近更新 更多