2013-03-27 6 views
0

Я недавно начал использовать Entity Framework и первую миграцию кода. Мое приложение теперь «живое», и я начинаю видеть, что все идет медленно. Моя база данных содержит около 30 000 строк в таблице, которые используются больше всего.Оптимизация объединения Entity Framework

Это метод, который я возвращаю много, как я к таблицам, один с данными сообщения, и один с каждым получателем:

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 попросить сообщения выше определенного timestamp и аналогичные действия.

Мой вопрос: Можно ли оптимизировать этот запрос?

Это план выполнения наиболее часто используемых запросов:

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 –

ответ

1

Несвязанной к конкретным вопросам, под рукой (что Moho отвеченных частично уже) ...

Вы также можете попробовать 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?

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

+0

Хотя вы можете использовать свойство навигации, сам запрос не может быть оптимизирован. Вы уже используете проекцию, которая сужает набор результатов, и требуется соединение. Это должна быть проблема с индексацией. 30 000 строк - «ничего».Или одно из полей - большой объект («Сообщение», может быть?). –

+0

Может быть много MessageRecipients для каждого NewMessageItems, я не вижу, как я могу заставить msg.MessageRecipient работать без участия? Нет объекта MessageRecipient на msg Также; когда он находит индекс, как его «использовать»? Спасибо за помощь! – Sindre

Смежные вопросы