0

最近、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# ではどのように見えるでしょうか?

4

2 に答える 2

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
    };
于 2013-03-27T18:37:31.517 に答える