2010-03-23 78 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子句中。