DbSet<TEntity>.Local.Any() 将 EF Core 从 2.2.6 升级到 3.1.3 时出现性能问题

DbSet<TEntity>.Local.Any() performance issue when upgraging EF Core from 2.2.6 to 3.1.3

有一种方法负责根据我们的 git 提交缓存数据库 table 中的哈希返回单个 GitCommit 对象。我们使用 Entity Framework Core,当我 将 nuget 包从 2.2.6 升级到 3.1.3 时,我意识到一个奇怪的性能问题。从第二次调用 2.2.6 的方法开始,条件 _dbContext.GitCommitCache.Local.Any() 在 3.1 上执行了 0-1ms .3 通常需要 150-220ms。我 运行 这个方法大约 9 到 1 万次,这是一个巨大的性能瓶颈。是否有任何相关的内容在幕后发生了变化?这是否有任何简单的解决方案来保持原始性能?

    public async Task<GitCommit> GetCommitAsync(string hash)
    {
        try
        {
            await _semaphore.WaitAsync();
            if (!_dbContext.GitCommitCache.Local.Any())
            {
                await _dbContext.GitCommitCache.LoadAsync();
            }
            var cacheEntry = await _dbContext.GitCommitCache.FindAsync(hash);

            if (cacheEntry != null)
            {
                return cacheEntry;
            }

            var commit = await GetCommitDataAsync(hash);

            try
            {
                _dbContext.GitCommitCache.Add(commit);
                await _dbContext.SaveChangesAsync();
            }
            catch (DbUpdateException)
            {
                _dbContext.Entry(commit).State = EntityState.Detached;
            }

            return commit;
        }
        finally
        {
            _semaphore.Release();
        }
    }

issue #14001中,即EF core 3.0.0,新增访问Local时调用DetectChanges

public override LocalView<TEntity> Local
{
    get
    {
        CheckKey();

        if (_context.ChangeTracker.AutoDetectChangesEnabled)
        {
            _context.ChangeTracker.DetectChanges();
        }

        return _localView ??= new LocalView<TEntity>(this);
    }
}

DetectChanges 是一种复杂的方法,因此相对较慢。幸运的是,如您所见,如果您暂时禁用 AutoDetectChangesEnabled,只是为了调用 Local,您将再次加快速度。

我认为这样做是安全的,前提是当您输入该方法时 _dbContext 中没有未检测到的更改。