10

我注意到将 .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 开头的所有客户。我通过数据库调用而不是在内存中进行所有查询。

哪种方法更有效?

4

1 回答 1

28

注意:我在查询中使用了实体框架“上下文”。答案适用于实体框架或 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);

上面的行实际上并没有查询数据库中的可爱小狗。相反,它构建了一个查询,该查询将在未来某个时候查询小狗。这称为延迟执行。测验问题:上例中的“数据”是什么类型?

当您枚举变量数据时,查询实际上是运行的。此变量的类型为 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();

现在,数据是列表类型。在后台,这会创建一个 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); }

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

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 服务器计算小狗的数量,并且永远不会浪费带宽或内存,实际上将小狗从数据库中加载出来或将其发送到 C# 或任何其他地方。

我希望这有帮助!

于 2014-01-28T15:15:49.293 回答