2013-03-27 99 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