我正在编写一个处理大量图像的替换系统。我已经迁移了被认为是"生活"图像到新数据库,但需要通过UI搜索旧数据库,以允许用户拉出不同的图像。
我在我的数据库中放置了一个查询旧数据库的视图,以便我可以通过Entity Framework公开它。该视图效果很好,尽管有数百万条记录,但我得到的结果还不错。
我的问题是当我尝试使用LINQ to Entities运行查询时。我的搜索被分页,并将结果限制为每页100个。
我有一个IQueryable用于过滤结果,但对于Skip / Take我必须添加一个订单。下面的例子显示了获得结果的第2页(Skip 100,Take 100)。
Array
(
[0] => https://media.lewatmana.com/cam/tbicibubur/248/snapshot20180330_163142M-thumb.jpg
)
它生成的SQL是:
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();
问题似乎是对第一个投影进行了全面评估(大约1000万条记录),然后在返回前100行之前对其进行排序。查询执行计划将SORT成本显示为批次的92%。
这个查询大约需要30秒,只是在超时的尖端,所以它的命中和错过甚至是否返回。
我正在寻找关于如何提高速度的一些提示,针对视图的查询非常快(<1秒)。
答案 0 :(得分:1)
我写完这个问题的结尾,然后采取了一种略有不同的方法。无论如何,我以为我会发帖,因为它可能有用。
我改变了我的代码结构。我现在先做一个扩展的.Take()。这使我获得了所有页面,包括我想要返回的页面。然后我按顺序跳过,只跳过我想要的页面。
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
原始的Skip / Take导致以下SQL,它需要以前完全评估的内部查询,并且速度很慢:
query = query
.Take((page.GetValueOrDefault(0) + 1) * recordCount.GetValueOrDefault(100));
// Now skip to the required page.
daResults = daResults
.OrderBy(x => x.Id)
.Skip(page.GetValueOrDefault(0) * recordCount.GetValueOrDefault(100))
.ToList();
更改它,内部查询要小得多。该内部子查询使用SELECT TOP(200),它快速闪电,然后将OFFSET等应用于减少的结果
我仍然只是在所有这些事件发生之后枚举结果(.ToList()),所以这一切都停留在数据库中,结果现在又很快了。