2013-03-27 98 views
0

我最近開始使用實體框架和代碼第一次遷移。我的應用程序現在是「現場」,我開始看到事情進展緩慢。我的數據庫在表中有大約30.000行,用得最多。實體框架連接優化

這是因爲我有返回很多的方法,以表,一個與該消息數據,和一個與每個收件人:

IQueryable<CompleteMessageModel> completeMessageModels = 
    from msg in db.NewMessageItems 
    join mr in db.MessageRecipients on msg.MessageId equals mr.MessageId 
    select 
    new CompleteMessageModel() 
    { 
      MessageId = msg.MessageId, 
      RecipientMessageId = mr.MessageRecipientId, 
      Title = msg.Title, 
      Message = msg.Message, 
      Recipients = msg.Recipients, 
      AuthorUserId = msg.AuthorId, 
      RecipientUserId = mr.RecipientId, 
      StatusCode = mr.StatusCode, 
      Timestamp = msg.Timestamp, 
      IsRead = mr.ReadTimestamp > 0, 
      ReadTimestamp = mr.ReadTimestamp, 
      GeoTag = msg.GeoTag 
    }; 

然後,我使用此的IQueryable索要消息高於某一時間戳和類似的行爲。

我的問題是:該查詢是否可以進一步優化?

這是最常用的查詢執行計劃:

SELECT TOP (90) 
[Project1].[MessageId] AS [MessageId], 
[Project1].[MessageRecipientId] AS [MessageRecipientId], 
[Project1].[Title] AS [Title], 
[Project1].[Message] AS [Message], 
[Project1].[Recipients] AS [Recipients], 
[Project1].[AuthorId] AS [AuthorId], 
[Project1].[RecipientId] AS [RecipientId], 
[Project1].[StatusCode] AS [StatusCode], 
[Project1].[Timestamp] AS [Timestamp], 
[Project1].[C1] AS [C1], 
[Project1].[ReadTimestamp] AS [ReadTimestamp], 
[Project1].[GeoTag] AS [GeoTag] 
FROM (SELECT 
    [Extent1].[MessageId] AS [MessageId], 
    [Extent1].[Message] AS [Message], 
    [Extent1].[Title] AS [Title], 
    [Extent1].[AuthorId] AS [AuthorId], 
    [Extent1].[Timestamp] AS [Timestamp], 
    [Extent1].[Recipients] AS [Recipients], 
    [Extent1].[GeoTag] AS [GeoTag], 
    [Extent2].[MessageRecipientId] AS [MessageRecipientId], 
    [Extent2].[RecipientId] AS [RecipientId], 
    [Extent2].[ReadTimestamp] AS [ReadTimestamp], 
    [Extent2].[StatusCode] AS [StatusCode], 
    CASE WHEN ([Extent2].[ReadTimestamp] > 0) THEN cast(1 as bit) WHEN (NOT ([Extent2].[ReadTimestamp] > 0)) THEN cast(0 as bit) END AS [C1] 
    FROM [dbo].[NewMessageModels] AS [Extent1] 
    INNER JOIN [dbo].[MessageRecipients] AS [Extent2] ON [Extent1].[MessageId] = [Extent2].[MessageId] 
    WHERE ([Extent2].[RecipientId] = @p__linq__0) AND (1 <> [Extent2].[StatusCode]) AND (3 <> [Extent2].[StatusCode]) AND ([Extent1].[Timestamp] >= @p__linq__1) 
) AS [Project1] 
ORDER BY [Project1].[Timestamp] DESC 

如果它可以被優化,怎麼會有這一下在C#中?

+0

http://stackoverflow.com/questions/21051612/entity-framework-join-3-tables – 2017-02-11 05:59:53

回答

1

在您的linq查詢中不需要連接 - 只需在投影中訪問msg.MessageRecipient nav屬性即可。它將通過減少返回給您在投影中使用的字段的字段數來簡化您的SQL語句,但該連接仍然是必需的。

例如改變

RecipientMessageId = mr.MessageRecipientId 

RecipientMessageId = msg.MessageRecipient.MessageRecipientId 

檢查SSMS中生成的腳本的執行計劃 - 它應該提出一個指標,這將提高性能。

編輯:修改您的示例以刪除不必要的linq連接。您訪問導航屬性像任何其他財產的投影:

IQueryable<CompleteMessageModel> completeMessageModels = 
    from msg in db.NewMessageItems 
    //join mr in db.MessageRecipients on msg.MessageId equals mr.MessageId 
    select 
    new CompleteMessageModel() 
    { 
      MessageId = msg.MessageId, 
      RecipientMessageId = msg.MessageRecipient.MessageRecipientId, 
      Title = msg.Title, 
      Message = msg.Message, 
      Recipients = msg.Recipients, 
      AuthorUserId = msg.AuthorId, 
      RecipientUserId = msg.MessageRecipient.RecipientId, 
      StatusCode = msg.MessageRecipient.StatusCode, 
      Timestamp = msg.Timestamp, 
      IsRead = msg.MessageRecipient.ReadTimestamp > 0, 
      ReadTimestamp = msg.MessageRecipient.ReadTimestamp, 
      GeoTag = msg.GeoTag 
    }; 
+0

謝謝您的寶貴答覆。你如何訪問投影中的一個屬性?你有代碼示例或鏈接顯示如何做到這一點? – Sindre 2013-03-27 18:42:48

+0

儘管您可以使用導航屬性,但查詢本身無法進行優化。您已經使用投影,這會縮小結果集,並且需要連接。它必須是一個索引問題。 30,000行是「沒有」。或者其中一個字段是一個大對象('Message'也許?)。 – 2013-03-27 19:19:14

+0

對於每個NewMessageItems,可能會有許多MessageRecipients,我沒有看到如何讓msg.MessageRecipient在沒有連接的情況下工作? msg上沒有MessageRecipient對象 另外;當它找到一個索引時,我該如何「使用它」?感謝您的幫助! – Sindre 2013-04-06 08:50:12