C# 当EF使用ROW_NUMBER()进行排序和分页时,性能会受到影响

C# 当EF使用ROW_NUMBER()进行排序和分页时,性能会受到影响,c#,sql-server,entity-framework,entity-framework-6,C#,Sql Server,Entity Framework,Entity Framework 6,我的数据库中有一个实体视图,代码中有一个表示视图的实体类。要获得某个页面的结果,我将执行以下操作: var result=await dbContext.Entity .OrderByDescending(e=>e.CreatedOn) .然后按降序(e=>e.Id) .Skip((当前页-1)*itemsPerPage) .Take(itemsPerPage) .ToListAsync(); 对于50个项目的第一页(currentPage=1,itemsPerPage=50),EF生成以下内

我的数据库中有一个
实体
视图,代码中有一个表示视图的
实体
类。要获得某个页面的结果,我将执行以下操作:

var result=await dbContext.Entity
.OrderByDescending(e=>e.CreatedOn)
.然后按降序(e=>e.Id)
.Skip((当前页-1)*itemsPerPage)
.Take(itemsPerPage)
.ToListAsync();
对于50个项目的第一页(
currentPage=1
itemsPerPage=50
),EF生成以下内容:

选择
[Extent1]。[OrderId]作为[Id],
[Extent1].[Number]作为[CreatedOn],
...
从[dbo].[Entity]到[Extent1]
按行排序(按[Extent1].[CreatedOn]DESC[Extent1].[Id]DESC排序)
偏移量0行仅取下50行
问题是查询执行的时间很长。这就是为什么我尝试不使用row_number(),而且速度更快,我得到了相同的结果:

选择
[Extent1]。[OrderId]作为[Id],
[Extent1].[Number]作为[CreatedOn],
...
从[dbo].[Entity]到[Extent1]
按[Extent1].[CreatedOn]DESC[Extent1].[Id]DESC订购
偏移量0行仅取下50行
因此,我的问题是:
1) 为什么这里通常使用行号?
2) 为什么强制EF在这个查询中不使用它


更新:在视图使用的表上添加聚集索引有助于提高性能。谢谢

看看这是否更快:

var result = await dbContext.Entity
    .OrderByDescending(e => e.CreatedOn)
    .ThenByDescending(e => e.Id)
    .Select((x,i) => new {index = i, item = x})
    .GroupBy(x => x.index / itemsPerPage)
    .Select(x => x.Select(y => y.item).ToList())
    .ToListAsync();

看看这是否更快:

var result = await dbContext.Entity
    .OrderByDescending(e => e.CreatedOn)
    .ThenByDescending(e => e.Id)
    .Select((x,i) => new {index = i, item = x})
    .GroupBy(x => x.index / itemsPerPage)
    .Select(x => x.Select(y => y.item).ToList())
    .ToListAsync();

1.使用它是因为跳过和执行。2.如果确实要改进查询,请不要使用skip/take,因为您需要对其进行分析。您可以通过查看执行计划来实现这一点,然后确定执行计划缓慢的原因。在Sql Server上搜索查询执行计划以开始。我猜SSMS执行计划视图将推荐CreatedOn和Id上的一些索引。如果列Id是聚集索引,并且是标识列(意味着它随每个新记录递增X)那么你只能在上面应用排序,这应该会有很大的不同。这是假设CreatedOn在创建记录时被分配了当前日期时间值。@Igor谢谢您的回答!我无法为视图创建任何索引,因为它没有绑定架构(它有同义词)。我简化了一点,实际上,CreatedOn是动态值,我必须按一些动态值排序,然后按Id排序。但我不明白为什么“skip”和“take”需要row_number()。如果没有row_number(),我会得到不同的结果吗?我会研究查询的执行计划,但会去掉row_number()帮助1。使用它是因为跳过和执行。2.如果确实要改进查询,请不要使用skip/take,因为您需要对其进行分析。您可以通过查看执行计划来实现这一点,然后确定执行计划缓慢的原因。在Sql Server上搜索查询执行计划以开始。我猜SSMS执行计划视图将推荐CreatedOn和Id上的一些索引。如果列Id是聚集索引,并且是标识列(意味着它随每个新记录递增X)那么你只能在上面应用排序,这应该会有很大的不同。这是假设CreatedOn在创建记录时被分配了当前日期时间值。@Igor谢谢您的回答!我无法为视图创建任何索引,因为它没有绑定架构(它有同义词)。我简化了一点,实际上,CreatedOn是动态值,我必须按一些动态值排序,然后按Id排序。但我不明白为什么“skip”和“take”需要row_number()。如果没有row_number(),我会得到不同的结果吗?我会研究查询的执行计划,但不管怎样,如果去掉row_number()帮助,我相信EF在使用select(带int参数)时会引发异常,因为它无法转换为SQL语句。代码不处理实体的输出吗?如果我将查询分为两个查询,它会工作吗?第一个查询按顺序执行,第二个查询按页面分组?我相信EF在使用select(带int参数)时会引发异常,因为它无法转换为SQL语句。代码不处理实体的输出吗?如果我将查询分为两个查询,它会工作吗?第一个查询执行顺序,第二个查询执行按页面分组?