0

Logsエンティティがあり、そこから2つの継承されたエンティティがあります。継承された各エンティティは、別の異なるエンティティにリンクします。ResponseLogとSessionLogは、それぞれResponseエンティティとSessionエンティティに接続します。

Logsテーブルには70万をはるかに超えるレコードがあり、数百万に成長すると予想されます。

私がやりたいのは、ログテーブルから上位100のエントリを取得し、それらをリストに入れることです。

        var LogResults = (from entries in this.DbContext.LogEntries
                          orderby entries.TimeStamp descending
                          select entries).Take(nEntries);

ただし、これを行うとList<LogEntry> LogResultList= LogResults.ToList();、完了するまでに約45秒かかります。'ToList'関数は、データベースとのトランザクションが実際に行われるときのものであることに気付きましたが、nEntries = 100、25、または10000のいずれであっても、かかる時間は同じです。

linqが生成するクエリを調べたところ、上位100を取得する前に、ログテーブル内のすべてのログエントリ(700k +)のタイプを評価しているようです。

トップ100を取得し、それらのレコードだけが継承されたタイプを特定する方法はあります

生成されるSQLは次のとおりです。

    SELECT TOP (100) 
[Project3].[C1] AS [C1], 
[Project3].[Id] AS [Id], 
[Project3].[Message] AS [Message], 
[Project3].[TimeStamp] AS [TimeStamp], 
[Project3].[UserId] AS [UserId], 
[Project3].[SeverityLevelRaw] AS [SeverityLevelRaw], 
[Project3].[C2] AS [C2], 
[Project3].[C3] AS [C3]
FROM ( SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Message] AS [Message], 
    [Extent1].[TimeStamp] AS [TimeStamp], 
    [Extent1].[UserId] AS [UserId], 
    [Extent1].[SeverityLevelRaw] AS [SeverityLevelRaw], 
    CASE WHEN ( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL))) THEN '0X' WHEN (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL) AND ( NOT (([Project2].[C1] = 1) AND ([Project2].[C1] IS NOT NULL)))) THEN '0X0X' ELSE '0X0X0X' END AS [C1], 
    CASE WHEN ( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL))) THEN CAST(NULL AS uniqueidentifier) WHEN (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL) AND ( NOT (([Project2].[C1] = 1) AND ([Project2].[C1] IS NOT NULL)))) THEN [Project1].[SessionId] ELSE [Project1].[SessionId] END AS [C2], 
    CASE WHEN ( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL))) THEN CAST(NULL AS uniqueidentifier) WHEN (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL) AND ( NOT (([Project2].[C1] = 1) AND ([Project2].[C1] IS NOT NULL)))) THEN CAST(NULL AS uniqueidentifier) ELSE [Project2].[ResponseId] END AS [C3]
    FROM   [dbo].[LogEntries] AS [Extent1]
    LEFT OUTER JOIN  (SELECT 
        [Extent2].[SessionId] AS [SessionId], 
        [Extent2].[Id] AS [Id], 
        cast(1 as bit) AS [C1]
        FROM [dbo].[LogEntries_RuntimeLogEntry] AS [Extent2] ) AS [Project1] ON [Extent1].[Id] = [Project1].[Id]
    LEFT OUTER JOIN  (SELECT 
        [Extent3].[ResponseId] AS [ResponseId], 
        [Extent3].[Id] AS [Id], 
        cast(1 as bit) AS [C1]
        FROM [dbo].[LogEntries_ResponseLogEntry] AS [Extent3] ) AS [Project2] ON [Extent1].[Id] = [Project2].[Id]
)  AS [Project3]
ORDER BY [Project3].[TimeStamp] DESC
4

1 に答える 1

3

実行計画をご覧になることをお勧めします。おそらく、TimeStampにインデックスを追加する必要があります。

Microsoft SQL Server Management Studioで、クエリエディターの上にあるアイコンの上にマウスを置き、[実際の実行プランを含める]というラベルの付いたアイコンをクリックします。次に、クエリを再実行します。

結果の横に「実行プラン」というタブがあることに注意してください。これは、時間がかかりすぎるクエリのトラブルシューティングに非常に優れたツールです。実行プランのアイコンにマウスを合わせると、通常は右から左に、データベースエンジンがクエリの実行をどのように決定したか、および何に時間がかかっているかを確認できます。

Joe Changの記事http://www.qdpma.com/cbo/s2kcbo_2a.htmlには、SQLServer実行プランにあるさまざまな種類の実行ステップを理解するのに役立つ可能性があります。一般に、バルクスキャンやインデックススキャン(基本的には上から下に検索して何かを見つける)に多くの時間を費やしたくはありません。代わりに、インデックスシーク操作(通常、btreeバイナリ風検索)を確認する必要があります。

ほとんどの時間をスキャンまたは大規模な並べ替え操作に費やしていることに気付くと思います。TimeStamp列にインデックスを追加してみてください。この場合、クエリは1秒未満になります。

于 2012-12-17T21:11:36.770 に答える