使用分页优化的 Linq to SQL 查询

Linq to SQL query with paging optimization

我有一个查询,它从包含日志记录数据的 table 中选择条目。 table 包含大约 100 万个数据集。问题是这个查询需要很长时间才能完成。我尝试了查询的一些变体,但性能仍然很差,尤其是最后的页面。

Expression<Func<EventLogEntry, bool>> search = c => true;
if (!string.IsNullOrEmpty(param.sSearch))
{
    search = c => c.Message.Contains(param.sSearch) ||
        c.Source.Contains(param.sSearch) ||
        c.Category.Contains(param.sSearch);
}

using (DbContext db = new DbContext())
{
    logs = db.Logs
        .Where(search)
        .OrderByDescending(x => x.Timestamp)
        .Skip(param.iDisplayStart)
        .Take(param.iDisplayLength)
        .ToArray();
}

即使没有搜索词,查询也至少需要 10 秒。生成的 SQL 如下所示:

SELECT TOP (10) 
[Extent1].[EventId] AS [EventId], 
[Extent1].[Id] AS [Id], 
[Extent1].[EntryType] AS [EntryType], 
[Extent1].[Message] AS [Message], 
[Extent1].[Category] AS [Category], 
[Extent1].[Source] AS [Source], 
[Extent1].[Timestamp] AS [Timestamp], 
[Extent1].[Server_Id] AS [Server_Id]
FROM ( SELECT [Extent1].[Id] AS [Id], [Extent1].[EntryType] AS [EntryType], [Extent1].[Message] AS [Message], [Extent1].[EventId] AS [EventId], [Extent1].[Category] AS [Category], [Extent1].[Source] AS [Source], [Extent1].[Timestamp] AS [Timestamp], [Extent1].[Server_Id] AS [Server_Id], row_number() OVER (ORDER BY [Extent1].[Timestamp] DESC) AS [row_number]
    FROM [dbo].[EventLogEntries] AS [Extent1]
)  AS [Extent1]
WHERE [Extent1].[row_number] > 0
ORDER BY [Extent1].[Timestamp] DESC

有什么方法可以加快这个查询的速度吗?

指数是您的朋友。评论中对此进行了讨论,但我会添加更多细节而不是僵尸问题。

因为排序是在Timestamp的基础上进行的,而且跳取又与顺序有关,所以在Timestamp上加一个索引可以让服务器加快排序速度和分页。

用于过滤或连接的任何列的索引通常也有帮助,但对基于 Contains 的过滤器帮助不大。

如果您稍后执行 Select() 以便最终只使用某些列,那么带有 Using 的索引会有所帮助,例如如果你有

`….Select(l => new {l.Id, l.EntryType, l.Message})`

然后 Timestamp 上使用 INCLUDE(Id, EntryType, Message) 的索引将允许仅从索引完成查询。但是,当所有列都被使用时,这并没有太大好处,因此您只会得到使用大量 space 并减慢插入速度的大型索引的缺点。因此,它在这里没有价值,但值得了解它如何使类似案例受益。

同样,如果可能,请避免使用 ToArray(),而是在结果出现时对其进行处理。这提供了更快的获得第一个结果的时间、更快的总时间和更少的内存使用。