C# 添加.ToArray或.ToList是否总是使数据库查询更快?

C# 添加.ToArray或.ToList是否总是使数据库查询更快?,c#,linq,performance,toarray,C#,Linq,Performance,Toarray,我注意到,向查询添加.ToArray()或.ToList()时,数据库查询运行得更快。这是因为数据集被加载到内存中,所有后续查询都在内存中完成,而不是执行进一步昂贵的数据库调用吗 数据库查询的内存存储限制应该是多少,因为我担心占用过多的内存会降低整个项目的速度,因为我确信占用过多的内存存储会显著降低速度 编辑:这是用于Linq SQL查询的。我正在使用SQLServer2008 示例1:在内存中执行大型数据库查询和筛选 我有一个5000行的数据库表。我查询整个表(例如,从客户端选择*)。我接下来

我注意到,向查询添加.ToArray()或.ToList()时,数据库查询运行得更快。这是因为数据集被加载到内存中,所有后续查询都在内存中完成,而不是执行进一步昂贵的数据库调用吗

数据库查询的内存存储限制应该是多少,因为我担心占用过多的内存会降低整个项目的速度,因为我确信占用过多的内存存储会显著降低速度

编辑:这是用于Linq SQL查询的。我正在使用SQLServer2008

示例1:在内存中执行大型数据库查询和筛选

我有一个5000行的数据库表。我查询整个表(例如,从客户端选择*)。我接下来的几个查询基于上一个查询中的字段:a)获取所有男性客户;b) 获取所有女性客户c)获取名字以A开头的所有客户

示例2:执行更频繁的数据库调用

使用具有5000行的同一客户机表,我需要执行3个查询a)获取所有男性客户机;b) 获取所有女性客户机c)获取FirstName以A开头的所有客户机。我通过数据库调用而不是在内存中执行所有查询


哪种方法更有效?

注意:我在查询中使用了实体框架“上下文”。答案适用于实体框架或LINQtoSQL

ToArray()和ToList()永远不会加快查询速度。但是,如果您意外地多次运行查询,它们可能会使查询看起来像这样。这是使用LINQ时的常见错误。例如:

// Construct a query to find all the cute puppies
var data = myContext.Puppies.Where(puppy => puppy.Type == PuppyTypes.Cute);
上面这一行实际上并没有查询数据库中是否有可爱的小狗。相反,它构造了一个查询,在将来的某个时刻,它将查询小狗。这称为延迟执行。问答题:上例中的“数据”是什么类型

当您枚举变量数据时,实际上会运行查询。此变量的类型为IEnumerable。IEnumerables不同于列表或数组。IEnumerable仅仅是一个可以获得数据的承诺。这并不意味着你真的有数据

// Display the puppies
foreach (Puppy p in data) { Console.WriteLine(p.Name); }
上面的foreach调用将强制执行查询。小狗将出现在屏幕上,但它们不会缓存在数组或列表中的任何位置。现在,如果你这样做:

// Display their owner's names
foreach (Puppy p in data) { Console.Writeline(p.OwnerName); }
此foreach导致再次执行查询。事实上,如果在两次调用之间在数据库中添加或删除了新的小狗,您甚至可能会得到不同的结果!因此,假设我们将ToList()添加到初始调用中

// Construct a query to find all the cute puppies
var data = myContext.Puppies.Where(puppy => puppy.Type == PuppyTypes.Cute).ToList();
现在,数据的类型是List。在引擎盖下,这将创建一个IEnumerable,然后通过它执行foreach,并将结果放入列表中。所以现在,如果您显示小狗的名字和主人,它将不会查询数据库两次。相反,它在列表中循环了两次

如果您搜索延迟执行,您会发现它有很多有趣的用途,以及我列出的警告。通常,您希望确保只运行一次查询。如果这需要一个托利斯特()那太好了。但不要不必要地添加ToList()。使用最后一个示例:

var data = myContext.Puppies.Where(puppy => puppy.Type == PuppyTypes.Cute).ToList();
foreach (Puppy p in data) { Console.WriteLine(p.Name + "," + p.OwnerName); }
你应该把收费表放在这里吗?不因为当你真的不需要列表时,这会增加列表的开销。更糟糕的是:

var data = myContext.Puppies.Where(puppy => puppy.Type == PuppyTypes.Cute).ToList();
Console.Writeline(data.Count());
那更糟!它把所有的小狗都列在记忆里,然后数一数。但这种质疑根本不需要抓住小狗。这样做:

var data = myContext.Puppies.Where(puppy => puppy.Type == PuppyTypes.Cute);
Console.Writeline(data.Count());
它实际上告诉SQL server计算小狗的数量,并且从不浪费带宽或内存,实际上是将小狗从数据库中加载或发送到C#或其他任何地方


我希望这有帮助

它几乎只是以一种非常简单的伪装进行缓存。既然可以运行一次并记住结果,为什么每次都要花2分钟反复运行查询?不幸的是,这个问题没有明确的答案。你需要了解每一个案例。你不能把
ToArray
应用于所有情况,它不会让事情变得更快。至于任何限制,谁知道呢?这取决于很多事情。你需要给出一个具体的例子。在某些情况下,它会使事情变得更慢,例如在过滤之前拉入整个数据库表?EF?不管怎样,.ToArray()和.ToList()都是在IEnumerable上运行的扩展方法,它们实际“枚举”结果。在实际需要枚举的IEnumerable之前,它将推迟执行并尝试生成最有效的表达式以返回枚举结果。通过调用.ToArray()或.ToList()提前枚举结果(急切加载)需要预先处理,但允许您在不必枚举结果的情况下反复使用该查询。此外,使用
ToList()
ToArray()
将结果保存在内存中并不总能提供新数据。您将创建一些类似于捕获的东西,因此您需要不时更新数据以获取新数据。很好的回答我的朋友+1
此变量的类型为IEnumerable
-您的意思肯定是
IQueryable
@Jamiec是正确的。数据上下文返回一个IQueryable,它反过来也是一个IEnumerable。我不想深入IQueryable的细节。@Moby Disk
PuppyTypes.Cute
-太酷了!)回答得好,谢谢!