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

Mar*_*riS 10 c# linq performance toarray

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

对于数据库查询的内存存储应该有什么限制,因为我担心耗尽太多的内部内存会降低整个项目的速度,因为我确信占用过多的内存存储会大大减慢速度.

编辑:这是为Linq-SQL查询.我正在使用SQL Server 2008.

示例1:执行大型数据库查询并在内存中过滤

我有一个包含5 000行的数据库表.我查询整个表(例如SELECT*From Clients).我接下来的几个查询基于上一个查询中的字段:a)获取所有男性客户; b)获取所有女性客户c)获取FirstName以A开头的所有客户端.

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

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

哪种方法更有效?

Mob*_*isk 26

注意:我在查询中使用了实体框架"上下文".答案适用于Entity Framework或LINQ-to-SQL.

ToArray()和ToList()永远不会加速查询.但是,如果您不小心多次运行查询,它们可能会出现这种情况.这是使用LINQ时常见的错误.例如:

// Construct a query to find all the cute puppies
var data = myContext.Puppies.Where(puppy => puppy.Type == PuppyTypes.Cute);
Run Code Online (Sandbox Code Playgroud)

以上行实际上并不查询数据库中的可爱小狗.相反,它构造了一个查询,在将来的某个时候,查询小狗.这称为延迟执行.测验问题:上面例子中的"数据"是什么类型?

通过变量数据枚举时实际运行查询.此变量的类型为IEnumerable.IEnumebles与Lists或Arrays不同.IEnumerable仅仅是可以获得数据的承诺.这并不意味着您实际拥有数据.

// Display the puppies
foreach (Puppy p in data) { Console.WriteLine(p.Name); }
Run Code Online (Sandbox Code Playgroud)

上面的foreach调用将强制执行查询.小狗将进入屏幕,但它们不会被缓存在任何地方的数组或列表中.那么现在,如果你这样做:

// Display their owner's names
foreach (Puppy p in data) { Console.Writeline(p.OwnerName); }
Run Code Online (Sandbox Code Playgroud)

此foreach导致查询再次执行.事实上,如果在两次调用之间在数据库中添加或删除了新的小狗,您甚至可能得到不同的结果!因此,假设我们将ToList()添加到初始调用中.

// Construct a query to find all the cute puppies
var data = myContext.Puppies.Where(puppy => puppy.Type == PuppyTypes.Cute).ToList();
Run Code Online (Sandbox Code Playgroud)

现在,数据类型为List.在引擎盖下,这将创建一个IEnumerable,然后通过它进行foreach,并将结果放入列表中.现在,如果您显示小狗名称和所有者,它将不会两次查询数据库.它反而循环遍历列表两次.

如果你搜索延迟执行,你会发现很多有趣的用途,以及我列出的那些警告.通常,您希望确保只运行一次查询.如果那需要ToList()那么好.但是不要不必要地添加ToList().使用最后一个例子:

var data = myContext.Puppies.Where(puppy => puppy.Type == PuppyTypes.Cute).ToList();
foreach (Puppy p in data) { Console.WriteLine(p.Name + "," + p.OwnerName); }
Run Code Online (Sandbox Code Playgroud)

你应该在这里有ToList()吗?没有!因为当你真的不需要列表时,这会增加列表的开销.更糟:

var data = myContext.Puppies.Where(puppy => puppy.Type == PuppyTypes.Cute).ToList();
Console.Writeline(data.Count());
Run Code Online (Sandbox Code Playgroud)

那更糟糕!它把所有的小狗都拉进了记忆中的一个清单,然后计算它们.但是这个问题甚至根本不需要抓住小狗.这样做:

var data = myContext.Puppies.Where(puppy => puppy.Type == PuppyTypes.Cute);
Console.Writeline(data.Count());
Run Code Online (Sandbox Code Playgroud)

它实际上告诉SQL服务器计算小狗的数量,并且从不浪费带宽或内存实际将小狗从数据库中加载或将其发送到C#或其中任何一个.

我希望这有帮助!

  • `这个变量属于IEnumerable类型 - 当然你的意思是`IQueryable` (2认同)