2010-03-23 38 views
1

我刚开始学习LINQ to SQL,到目前为止,我对易用性和良好性能印象深刻。关于LINQ to SQL基础知识的问题

我曾经以为,从数据库时做LINQ查询,如

from Customer in DB.Customers where Customer.Age > 30 select Customer 

LINQ得到所有客户(“SELECT * FROM客户”),将其移至客户数组,然后让该搜索使用.NET方法的数组。这是非常低效的,如果数据库中有成千上万的客户呢?做出如此大的SELECT查询会终止Web应用程序。

现在遇到实际如何快速LINQ to SQL是后,我开始怀疑,这样做查询我刚写的时候,LINQ莫名其妙地将其转换为SQL查询字符串

SELECT * FROM Customers WHERE Age > 30 

而且只在必要时它会运行查询。

所以我的问题是:我是对吗?什么时候查询实际运行?

我问的原因不仅仅是因为我想了解它是如何工作以构建优化的应用程序,而是因为我遇到了以下问题。

我有两张桌子,其中一张是书籍,另一张有关于某些日子有多少书籍被出售的信息。我的目标是选择过去10天内每天至少销售50张的书籍。它与这个简单的查询做:

from Book in DB.Books where (from Sale in DB.Sales where Sale.SalesAmount >= 50 && Sale.DateOfSale >= DateTime.Now.AddDays(-10) select Sale.BookID).Contains(Book.ID) select Book 

问题是,我有几个查询使用检查的一部分,我决定建立一个与所有流行的书籍ID的数组:

var popularBooksIDs = from Sale in DB.Sales where Sale.SalesAmount >= 50 && Sale.DateOfSale >= DateTime.Now.AddDays(-10) select Sale.BookID; 

BUT当我尝试做现在的查询时:

from Book in DB.Books where popularBooksIDs.Contains(Book.ID) select Book 

它不起作用!这就是为什么我认为我们不能在LINQ to SQL查询中使用各种快捷方式,就像我们不能在真正的SQL中使用它们一样。我们必须创建简单的查询,对吗?

+0

为了适应速度,我强烈推荐LINQPad。这很难描述,但它基本上是LINQ查询,你可以很容易地看到后台发生了什么。非常适合测试新的查询。 http://www.linqpad.net/ – Steve 2010-03-23 21:09:56

回答

3

你是对的。 LINQ to SQL确实创建了实际的SQL来检索结果。

至于你的快捷方式,也有办法解决的局限性:

var popularBooksIds = DB.Sales 
    .Where(s => s.SalesAmount >= 50 
     && s.DateOfSale >= DateTime.Now.AddDays(-10)) 
    .Select(s => s.Id) 
    .ToList(); 

// Actually should work. 
// Forces the table into memory and then uses LINQ to Objects for the query 
var popularBooksSelect = DB.Books 
    .ToList() 
    .Where(b => popularBooksIds.Contains(b.Id)); 
1

是的,查询会被翻译成一个SQL字符串,而底层的SQL可能会因您尝试做什么而有所不同......所以您在这方面必须小心。签出一个名为linqpad的工具,你可以尝试你的查询并查看正在执行的SQL。

另外,它在遍历集合或调用ToList()方法时运行。

+0

所以没有办法使用这样的快捷方式,对吧?我想知道我在哪里可以找到一些资源来阅读这个。不幸的是书本没有解释这些概念。 – Alex 2010-03-23 18:22:01

+0

我的歉意,我错过了最后一部分。我确实收到包含在SQL查询中工作的内容......那么它不起作用,因为你会得到一个错误,或者没有结果返回?如果发生错误,则可能会在第一个查询中出现错误。否则,如果没有结果返回,就很难说不查看数据库查询; LinqPad可以提供帮助。 Contains是少数几个数组支持的方法之一,所以我不认为它是这样的,只要这两个对象是相同的类型(我的意思是两个ID)。 – 2010-03-23 19:30:08

1

实体框架或LINQ查询可能会非常棘手有时。有时候你会对生成的sql查询的效率感到惊讶,有时候查询太复杂而且效率低下,以致于会打击你的额头。

最好的想法是,如果您对查询有任何怀疑,请在后端运行一个sql profiler来监视所有进入的查询。这样您就可以确切地知道传递给sql server的内容并更正如果需要,效率低下。

1

http://damieng.com/blog/2008/07/30/linq-to-sql-log-to-debug-window-file-memory-or-multiple-writers

这将帮助你看到什么,当查询正在运行。此外,Damiens博客充满了其他的优点。

您可以使用.Any方法生成EXISTS子句。我比试图生成IN子句有更多的成功,因为它喜欢检索所有数据并将其全部作为参数传递回查询

在linq to sql中,可以将IQueryable表达式片段组合起来以创建一个单一的查询,在你做一些无法用SQL表达的东西之前,它会尽可能将所有东西都保存为IQueryable。当您调用ToList时,您直接要求它将该查询解析为存储在内存中的IEnumerable。

在大多数情况下,您最好不要提前选择书籍ID。将流行书籍的片段保留在代码中的一个位置,并在必要时使用它,以构建另一个查询。一个IQueryable只是一个表达式树,在其他一些地方被解析为SQL。

如果您认为您的应用程序通过在其他地方(memcache或其他)存储流行的书籍可以获得更好的性能,那么您可以考虑先将它们拉出来,然后再进行检查。这将意味着每个book id将作为sproc参数传入并用于IN子句中。