C# 在Azure SQL上排序时因超时而导致EF核心查询失败

C# 在Azure SQL上排序时因超时而导致EF核心查询失败,c#,sql-server,entity-framework,azure-sql-database,entity-framework-core,C#,Sql Server,Entity Framework,Azure Sql Database,Entity Framework Core,我有一个使用高级层托管在Azure上的数据库。 数据库有一个非常简单的表,其结构如下: Id PK uniqueidentifier Timestamp datetimeoffset TenantId uniqueidentifier other columns 表只有聚集索引 我的应用程序正在通过以下方式使用EF Core查询数据: dbContext .TaskRecords .Where(r => r.TenantId == tenantId) .OrderByDescending

我有一个使用高级层托管在Azure上的数据库。 数据库有一个非常简单的表,其结构如下:

Id PK uniqueidentifier
Timestamp datetimeoffset
TenantId uniqueidentifier
other columns
表只有聚集索引

我的应用程序正在通过以下方式使用EF Core查询数据:

dbContext
.TaskRecords
.Where(r => r.TenantId == tenantId)
.OrderByDescending(item => item.Timestamp)
.Skip(10)
.Take(10)
.ToListAsync();
在超过200000条记录的某个时间点,查询因超时而开始失败

EF core生成以下SQL查询:

exec sp_executesql N'SELECT [r].[Id],[r].[TenantId], [r].[Timestamp], [r].
[OTHER_COLUMNS]
FROM [TaskRecords] AS [r]
WHERE [r].[TenantId] =@__firmId_0
ORDER BY [r].[Timestamp] DESC
OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY',N'@__tenantId_0 uniqueidentifier,@__p_1 
int,@__p_2 int',@__tenantId_0 ='645B38D4-1009-47CF-8519-
182865827F22',@__p_1=0,@__p_2=10
当从SSMS或使用SqlCommand执行时,它表现良好,但在EF中失败

为Timestamp和TenantId列添加非聚集索引根本解决不了问题。 索引统计显示,聚集索引有99%的碎片。重建索引后,查询再次开始工作。但在达到15%的碎片查询超时后,查询开始失败

即使不重建索引,使用升序排序也可以工作

EF有什么问题?为什么它会这样

编辑:

重建索引不再有效。所以这可能只是巧合

编辑:

我花了一些时间使用EF Core 1.1.2和2.0版本的简单控制台应用程序来分析框架行为。 当从主方法调用查询时,查询执行良好且几乎立即执行,但当从另一个方法中调用查询时,查询将挂起:

static void Main(string[] args)
{
    var context = new DbContext(...);
    var result = context.TaskRecords
    .Where(r => r.TenantId == tenantId)
    .OrderByDescending(item => item.Timestamp)
    .Skip(10)
    .Take(10)
    .ToList(); // WORKS FINE

    result = GetRecords(); //FAILS BY TIMEOUT
}

public static List<TaskRecords> GetRecords()
{
    var context = new DbContext(...);
    return context.TaskRecords
    .Where(r => r.TenantId == tenantId)
    .OrderByDescending(item => item.Timestamp)
    .Skip(10)
    .Take(10)
    .ToList();
}
static void Main(字符串[]args)
{
var context=newdbcontext(…);
var result=context.TaskRecords
.其中(r=>r.TenantId==TenantId)
.OrderByDescending(项=>item.Timestamp)
.Skip(10)
.Take(10)
.ToList();//工作正常
结果=GetRecords();//超时失败
}
公共静态列表GetRecords()
{
var context=newdbcontext(…);
返回context.TaskRecords
.其中(r=>r.TenantId==TenantId)
.OrderByDescending(项=>item.Timestamp)
.Skip(10)
.Take(10)
.ToList();
}

我的TaskRecord实体包括18个属性。当我注释掉一个随机属性时,第二个调用将立即开始执行。

您是否检查了查询存储区中的执行计划以跟踪差异?为每个查询重新排序表的成本会很高,因此您可能需要(TenantId,Timestamp)上的索引来提高分页效率。EF中的超时值(
context.Database.CommandTimeout
)是多少,过低的值也会使同一查询失败。我还建议实时检查通过探查器检查的两个查询(来自EF和来自SSMS)。@DavidBrowne Microsoft,我按照您的建议创建了新索引,并正在监视系统的行为。目前没有问题。然而,我仍然想知道,当SSMS和SqlCommand查询在不到1秒的时间内完成时,为什么从EF运行时它的行为会有所不同。@lamCP,超时设置为30秒。我比较了执行计划,它们看起来很好,但服务器必须进行索引扫描。但我仍然怀疑它是否需要超过30秒才能完成。