C# Linq查询执行顺序

fdx2calv  于 2022-12-06  发布在  C#
关注(0)|答案(3)|浏览(142)

请考虑以下方法:

public IEnumerable<Owner> GetOwners(OwnerParameters ownerParameters)
{
    return FindAll()
        .OrderBy(on => on.Name)
        .Skip((ownerParameters.PageNumber - 1) * ownerParameters.PageSize)
        .Take(ownerParameters.PageSize)
        .ToList();
}

其中FindAll()是返回IQueryable<Owner>的存储库模式方法。在.Skip().Take()方法之前具有.OrderBy()是否意味着将检索和排序来自Owner数据表的所有元素,或者,Linq是否考虑到.Skip().Take()方法可能会缩小所需的Owner元素的范围,并且只有在检索到这些元素之后才会进行排序?
编辑:探查器日志:

SELECT XXX
FROM [Owners] AS [a]
ORDER BY [a].[Name]
OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY',N'@__p_0 int,@__p_1 int',@__p_0=0,@__p_1=10
balp4ylt

balp4ylt1#

最后,这取决于FindAll()执行的操作和返回的内容:

  • 如果它返回IEnumerable<T>,那么它使用的是LINQ-to-Objects,而LINQ-to-Objects * 大部分 * 只是字面上执行它被告知的内容;如果你排序然后页,那么 * 它 * 排序然后页;如果您先分页然后排序,则 it 分页然后排序
  • 但是,如果它返回IQueryable<T>,则查询正在 * 组合 * -并且只在ToList()中实际执行,此时提供程序模型有机会检查您的查询树并构建可能的最合适的实现,这通常意味着:编写SQL查询,该SQL查询包括ORDER BY和适合于特定RDBMS的一些分页提示;如果您的代码分页然后排序(这是...不寻常的),那么我会 * 期望 * 大多数提供程序 * 要么 * 编写某种可怕的子查询来尝试描述它,* 要么 * 只是厌恶地抛出一个异常(可能是NotSupportedException
ijxebb2r

ijxebb2r2#

不会检索所有记录。根据您的后端,将生成一个查询,该查询按名称排序,跳过N行并取下M行。仅检索查询结果,由.ToList()触发。即:在MS SQL服务器中,查询可能如下所示:

Select top(M) row_number() over (order by Name) as RowNo, * 
from myTable
where RowNo > N

这种类型的查询不是很有效,但这是另一回事,您可以创建自定义的解决方法。
编辑:我记得MS SQL代码生成错误。它是:

SELECT ...
FROM ...
ORDER BY ...
OFFSET x ROWS FETCH NEXT y ROWS ONLY

这个也很慢。如果你有速度考虑,那么你可以写你自己的SQL并用Linq发送。基本上你所做的就是保留lastRetrieved值并将其设置为一个参数:

select top(NTake) ... from ... 
order by ... 
where orderedByValue > @lastRetrievedValue

(You可以在Linq中发送原始SQL查询)

elcex8rz

elcex8rz3#

一个快速的例子来说明查询的顺序很重要。上面给出的解释很好。

var test1 = await _dbContext.UserActivityLogs
.Where(x => x.ExternalSyncLogId == request.Id)
.Skip(0).Take(25)
.AsNoTracking().ToListAsync();

此查询传递到

exec sp_executesql N'SELECT [u].[Id], [u].[ActionType], [u].[ActivityEndTime], [u].[ActivityStartTime], [u].[ActivityType], [u].[Created], [u].[CreatedBy], [u].[EntityId], [u].[ExternalSyncLogId], [u].[LastModified], [u].[LastModifiedBy], [u].[RequestBody], [u].[ResponseBody], [u].[Source], [u].[TenantId]
FROM [UserActivityLogs] AS [u]
WHERE ([u].[ExternalSyncLogId] IS NULL
ORDER BY (SELECT 1)
OFFSET @__p_1 ROWS FETCH NEXT @__p_2 ROWS ONLY',N'@__p_1 int,@__p_2 int',@__p_1=0,@__p_2=25

执行时间:第二十九届会议

但如果我们改变顺序

var test2 = await _dbContext.UserActivityLogs
.Skip(0).Take(25)
.Where(x => x.ExternalSyncLogId == request.Id)
.AsNoTracking().ToListAsync();

翻译为

exec sp_executesql N'SELECT [t].[Id], [t].[ActionType], [t].[ActivityEndTime], [t].[ActivityStartTime], [t].[ActivityType], [t].[Created], [t].[CreatedBy], [t].[EntityId], [t].[ExternalSyncLogId], [t].[LastModified], [t].[LastModifiedBy], [t].[RequestBody], [t].[ResponseBody], [t].[Source], [t].[TenantId]
FROM (
    SELECT [u].[Id], [u].[ActionType], [u].[ActivityEndTime], [u].[ActivityStartTime], [u].[ActivityType], [u].[Created], [u].[CreatedBy], [u].[EntityId], [u].[ExternalSyncLogId], [u].[LastModified], [u].[LastModifiedBy], [u].[RequestBody], [u].[ResponseBody], [u].[Source], [u].[TenantId]
    FROM [UserActivityLogs] AS [u]
    ORDER BY (SELECT 1)
    OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY
) AS [t]
WHERE [t].[ExternalSyncLogId] IS NULL',N'@__p_0 int,@__p_1 int',@__p_0=0,@__p_1=25

执行时间:小岛屿发展中国家

相关问题