0

我有一个 Logs 实体,它有两个继承的实体。每个继承的实体都链接到另一个不同的实体。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 个之前评估了 Log 表中每个日志条目(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可以帮助您了解在 SQL Server 执行计划中可以找到的不同类型的执行步骤。通常,您不希望在批量扫描或索引扫描中看到太多时间(本质上是从上到下搜索以查找某些内容)。相反,您希望查看索引查找操作(通常是 btree 二进制搜索)。

我希望您会发现大部分时间都花在了扫描或大型排序操作上。尝试在 TimeStamp 列上添加索引。我敢打赌,在这种情况下,它会将您的查询降到亚秒级。

于 2012-12-17T21:11:36.770 回答