实体框架连接优化

时间:2013-03-27 18:32:06

标签: c# sql-server-2008 entity-framework code-first

我最近开始使用Entity Framework并编写代码首次迁移。我的应用程序现在“正常”,我开始看到事情变得缓慢。我的数据库在表中有大约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#中会看到什么?

2 个答案:

答案 0 :(得分:1)

您不需要linq查询中的连接 - 只需访问投影中的msg.MessageRecipient nav属性即可。它将通过减少返回到您在投影中使用的字段的数量来简化SQL语句,但仍然需要连接。

e.g。变化

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
    };

答案 1 :(得分:1)

与你手头的具体问题无关(莫霍已经部分回答了)......

您还可以尝试performance tips,尤其是Performance Considerations for Entity Framework 5

  

最重要的是,下载EF Power Tools    - 并查看generate views功能。

有关更多信息,我几天前发布了一些更多的信息(只是一点但可能有帮助)。

Mapping View to Entity using EF 5 Code First

why when i want use EF Power tools for view my model i get error?