【发布时间】:2018-03-30 09:52:58
【问题描述】:
我正在编写一个处理大量图像的替换系统。我已将被视为“实时”图像的内容迁移到新数据库,但需要通过 UI 搜索旧数据库以允许用户拉取不同的图像。
我在我的数据库中放置了一个查询旧数据库的视图,以便我可以通过实体框架公开它。该视图运行良好,尽管有数百万条记录,但我很快就获得了结果。
我的问题是当我尝试使用 LINQ to Entities 运行查询时。我的搜索是分页的,并将结果限制为每页 100 个。
我有一个用于过滤结果的 IQueryable,但对于 Skip/Take,我必须添加一个 order by。下面的示例显示了获取结果的第 2 页(跳过 100,获取 100)。
if (firstId.HasValue)
query = query.Where(x => x.Id >= firstId.Value);
if (!string.IsNullOrEmpty(groupCode))
query = query.Where(x => x.GroupCode == groupCode);
var daResults = query
.OrderBy(x => x.Id)
.Skip(100)
.Take(100)
.ToList();
生成的 SQL 是:
SELECT
[Project1].[Id] AS [Id],
[Project1].[FolderPath] AS [FolderPath],
[Project1].[Filename] AS [Filename],
[Project1].[IsFlagged] AS [IsFlagged],
[Project1].[IsHidden] AS [IsHidden],
[Project1].[TextField1] AS [TextField1],
[Project1].[TextField2] AS [TextField2],
[Project1].[TextField3] AS [TextField3],
[Project1].[TextField4] AS [TextField4],
[Project1].[GroupCode] AS [GroupCode],
[Project1].[Deleted] AS [Deleted],
[Project1].[Created] AS [Created],
[Project1].[CreatedBy] AS [CreatedBy],
[Project1].[Updated] AS [Updated],
[Project1].[UpdatedBy] AS [UpdatedBy]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Extent1].[FolderPath] AS [FolderPath],
[Extent1].[Filename] AS [Filename],
[Extent1].[IsFlagged] AS [IsFlagged],
[Extent1].[IsHidden] AS [IsHidden],
[Extent1].[TextField1] AS [TextField1],
[Extent1].[TextField2] AS [TextField2],
[Extent1].[TextField3] AS [TextField3],
[Extent1].[TextField4] AS [TextField4],
[Extent1].[GroupCode] AS [GroupCode],
[Extent1].[Deleted] AS [Deleted],
[Extent1].[Created] AS [Created],
[Extent1].[CreatedBy] AS [CreatedBy],
[Extent1].[Updated] AS [Updated],
[Extent1].[UpdatedBy] AS [UpdatedBy]
FROM [dbo].[view_ProEditBulkImageInfo] AS [Extent1]
WHERE
([Extent1].[Deleted] IS NULL)
AND ([Extent1].[Id] >= 300000)
) AS [Project1]
ORDER BY row_number() OVER (ORDER BY [Project1].[Id] ASC)
OFFSET 100 ROWS FETCH NEXT 100 ROWS ONLY
问题似乎是第一个投影已被完全评估(大约 1000 万条记录),然后在返回前 100 行之前对其进行排序。查询执行计划将 SORT 成本显示为批处理的 92%。
这个查询大约需要 30 秒,就在超时的尖端,所以它是否会返回时时好时坏。
我正在寻找一些关于如何加快速度的提示,针对视图的查询非常快(
【问题讨论】:
-
您确定需要在获取页面之前先进行排序吗?
-
Linq 不应该只是语法糖。 Take 和 Skip 之所以慢,是因为它们被翻译为 OFFSET 和 FETCH,它们在大量记录上本来就很慢。看看here。
-
是否需要导航到任意页面,还是按顺序导航(第1页,然后是2,然后是3...)?
-
LINQ 不会让您在没有 OrderBy 的情况下跳过。
-
并且导航是按顺序进行的。用户通常会知道图像 Id,或者至少知道来自大约同一时间的图像的 Id,因此他们不太可能对结果进行过多的分页。
标签: c# linq-to-entities