Ошибка производительности DbSet <TEntity>.Local.Any () при обновлении EF Core с 2.2.6 до 3.1.3 - PullRequest
2 голосов
/ 07 апреля 2020

Существует метод, который отвечает за возврат одного объекта GitCommit на основе его ha sh из нашей таблицы базы данных git commit cache. Мы используем Entity Framework Core , и когда я обновил пакеты nuget с 2.2.6 до 3.1.3 , я обнаружил странную проблему с производительностью. Начиная со второго вызова метода с 2.2.6, условие _dbContext.GitCommitCache.Local.Any () заняло 0-1ms для выполнения, на 3.1.3 обычно занимает около 150-220ms . Я использую этот метод от 9 до 10 тысяч раз, и это огромное узкое место в производительности. Есть что-нибудь связанное, что изменилось под капотом? Есть ли в этом какие-то тривиальные решения для сохранения оригинальной производительности?

    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();
        }
    }

1 Ответ

2 голосов
/ 08 апреля 2020

В выпуске # 14001 , то есть EF core 3.0.0, было добавлено, что DetectChanges вызывается при доступе к Local:

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

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

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

DetectChanges является сложный и поэтому относительно медленный метод. К счастью, как вы видите, если вы временно отключите AutoDetectChangesEnabled, просто для вызова Local, вы снова наберете скорость.

Я думаю, что это безопасно, если предположить, что в незамеченных изменениях нет _dbContext при вводе метода.

...