【问题标题】:Does calling ToList multiple times effect performance?多次调用 ToList 会影响性能吗?
【发布时间】:2015-10-30 04:25:30
【问题描述】:

我经常看到调用 ToList 会使查询每次都被执行。我对此有点困惑。那么在这种情况下,第二次调用 ToList 是否会使查询多次执行?在什么情况下查询会多次执行?

//This gets from database and ToList is already called here
List<Customer> Customers = GetCustomersFromDataBase();

//ToList is called here again
List<Customer> FilteredCustomers = (from c in Customerswhere c.id == 1c).ToList();

编辑

我刚刚提供了这个代码示例来了解 ToList 的真正作用。我没有以这种方式实现它。 另外,我进行了一个存储过程调用以从 db 返回客户,并从返回的数据表中创建一个客户列表。

【问题讨论】:

  • 为什么要这样做?而是在调用 ToList() 后存储列表并使用它?
  • 请检查我的编辑。
  • 你是对 List() 做再次列表还是在 IQueryable 上?
  • 它是 LINQ 查询 (IQueryable) 而不是一个集合 (IEnumerable),它可能会被多次评估(可能会对性能造成重大影响),如果如果您不执行.ToList(),则在您的代码中多次引用。这可能取决于 LINQ 提供程序。

标签: c# linq


【解决方案1】:

IQueryable 上调用ToList(或ToArrayAsEnumerable 等)将执行查询。之后,您使用的任何 LINQ 表达式都将在内存列表中进行操作。

例如,您的代码:

List<Customer> Customers = GetCustomersFromDataBase();

这将产生代表数据库记录的Customer 对象中的List。该列表现在独立于用于从数据库中获取结果的查询,尽管仍需要从数据库中获取 Customer 对象中的链接记录。

那么当你这样做时:

List<Customer> FilteredCustomers = (from c in Customers where c.id == 1c).ToList();

这不是对数据库进行操作,而是对上一条语句返回的内存中的结果进行操作。在这种情况下,您不会多次查询数据库。

确实影响性能的地方是当您有一个 IQueryable 对象时,您可以直接多次调用 ToList。在IQueryable 上对ToList 的每次调用都将导致对数据库的调用,并在后台进行所有相关对象跟踪等。通常这是您要避免的事情,但如果查询选择的记录总数很大并且过滤器提取数据的小子集,则在枚举结果之前对查询进行额外过滤可能会导致更好的性能。

【讨论】:

  • 您的回答似乎很有道理!我想仔细检查一件事 - 如果我有一个返回 IQueryable 客户的 wcf 服务,那么每次我调用 ToList 时都会调用该服务吗?
  • 如果您调用 ToList 来获取内容,那么您可以在该结果上调用 ToList 而无需再次调用 WCF 查询。如果您在 WCF IQueryable 上调用 ToList,它将再次调用 WCF 服务以获取结果。
  • 换句话说,如果调用的目标是IQueryable,那么它将查询它们(数据库|WCF 服务|不管)。如果它是本地集合,则不查询(数据库/WCF/等)。
  • 我问的原因是因为我有一个 wcf 服务并且我试图不多次调用该服务。在调用 ToList 之前,我会进行大量过滤。这行得通,但稍后根据用户选择,我将不得不进一步过滤结果并再次调用 ToList。出于某种原因,即使它已经是内存中的对象,也会再次调用服务。
  • 你在AsEnumerable上是不正确的;它不执行查询,但这确实意味着当查询被执行时,AsEnumerable 调用之后的一部分由 linq-to-objects 执行,而不是由查询提供程序执行其余部分。
【解决方案2】:

在您的场景中,查询只执行一次。

这里:

List<Customer> FilteredCustomers = (from c in Customers where c.id == 1c).ToList();

此行仅基于变量Customers 进行过滤,该变量是由ToList() 填充的客户表的副本。

【讨论】:

  • 虽然它本身是一个很好的答案,但它不能解决 "所以在这种情况下,第二次调用 ToList 会使查询执行超过一次?在什么情况下查询会执行多次?"
【解决方案3】:

检查 Enumerable.ToList() 的源代码(谷歌) Enumerable.ToList()

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
    if (source == null) throw Error.ArgumentNull("source");
        return new List<TSource>(source);
}

所以是 ToList().ToList(),是浪费,创建了一个 new List,第一个 ToList 中的所有(引用)元素都复制到第二个中,导致新内存被分配并且第一个列表被垃圾收集,导致内存被释放。

【讨论】:

    猜你喜欢
    • 2018-04-03
    • 2013-03-09
    • 1970-01-01
    • 2015-01-10
    • 1970-01-01
    • 2021-02-18
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    相关资源
    最近更新 更多