Оптимизация SELECT запросов в Entity Framework 6: NOLOCK

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Для того чтобы внедрить поведение NOLOCK в Entity Framework 6, вам нужно поместить свои запросы в контекст TransactionScope с опцией IsolationLevel.ReadUncommitted:

csharp
Скопировать код
using (var scope = new TransactionScope(TransactionScopeOption.Required,
               new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted }))
{
    // Ваш запрос EF здесь будет выполнен с применением NOLOCK
    var query = context.Entities.ToList();
    
    // Обязательно выполните scope.Complete() для завершения транзакции.
    scope.Complete();
}

Примечание: При применении NOLOCK возможны грязные чтения. Поэтому использование этого подхода должно быть обдуманным.

Кинга Идем в IT: пошаговый план для смены профессии

Пользовательский перехват команд: Мастер маскировки

Для изменения SQL-команд без воздействия на базу данных вы можете использовать DbCommandInterceptor.

Утончённое использование перехватчиков

Создайте собственный перехватчик, унаследовав его от DbCommandInterceptor, и переопределите метод ReaderExecuting, добавив подсказку NOLOCK. Пример обработки:

csharp
Скопировать код
public class NoLockInterceptor : DbCommandInterceptor
{
    public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        // Делаем мягкую подстановку NOLOCK в SQL-команду
        command.CommandText = command.CommandText.Replace("FROM", "FROM (NOLOCK)");
        
        // Вызываем исходный метод ReaderExecuting
        base.ReaderExecuting(command, interceptionContext);
    }
}

Зарегистрируйте перехватчик в методе инициализации вашего приложения:

csharp
Скопировать код
DbInterception.Add(new NoLockInterceptor());

Обед не бесплатен

Применение NOLOCK может значительно увеличить производительность, однако это сопряжено с риском грязного чтения данных. Это может привести к чтению данных, еще не законфирмированных транзакцией, или к пропуску определенных строк.

Управление транзакциями: Держите утят в ряд

Транзакции — это еще один способ работы с данными, позволяющий избежать побочных эффектов от NOLOCK.

Применение TransactionScope

Управлять пакетными операциями предназначен TransactionScope:

csharp
Скопировать код
using (var transactionScope = new TransactionScope(TransactionScopeOption.Required, 
    new TransactionOptions { 
        IsolationLevel = IsolationLevel.ReadUncommitted 
    }))
{
    // Здесь применяются ваши операции с базой данных
    transactionScope.Complete();
}

Создайте интерцептор уровня изоляции

Создайте IsolationLevelInterceptor и добавьте его в конфигурацию EF DbConfiguration:

csharp
Скопировать код
public class IsolationLevelInterceptor : DbCommandInterceptor
{
    public override void ReaderExecuting(DbCommand command,
        DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        // Применяем ReadUncommitted только для текстовых команд
        if (command.CommandType == CommandType.Text)
            command.Connection.BeginTransaction(IsolationLevel.ReadUncommitted);

        // Выполняем вызов исходного метода ReaderExecuting
        base.ReaderExecuting(command, interceptionContext);
    }
}

Примечание: Не забывайте об освобождении ресурсов после выполнения команды.

Визуализация

Использование Entity Framework с NOLOCK можно сравнить с пользованием экспресс-кассой в супермаркете:

plaintext
Скопировать код
Без NOLOCK:  [🛒🚶🛒🚶🛒🥫🍞🥛]
             |----- Медленная очередь -----|
С NOLOCK:    [🚀🛒💨]
             |-- Экспресс-полоса --|

Entity Framework без NOLOCK: вы находитесь в очереди за базовыми продуктами.

Entity Framework с NOLOCK: вы проходите кассу быстро, но рискнуть пролить молоко (то есть столкнуться с проблемами с транзакциями).

Улучшение производительности: Предназначено для смельчаков

Попробуйте экспериментировать со следующими нестандартными методами улучшения производительности Entity Framework:

Профилирование и оптимизация: Покажите SQL, кто здесь главный

С помощью SQL Profiler вы можете наблюдать за эффективностью NOLOCK и определить узкие места.

Повторное использование соединения: Делиться значит быть внимательным

Пользуйтесь пулом соединений SqlConnectionPool, чтобы оптимизировать использование ресурсов, снизив затраты на установление соединений.

Контроль времени жизни транзакции: Всё — дело времени

Для контроля над продолжительностью транзакций удобно использовать расширение DataReaderDisposing в сценариях с IDataReader.

Чистый и поддерживаемый код: Мы все любим порядок

Решения как UnitOfWork и Repository позволяют лаконично объединить логику управления транзакциями с перехватом команд.

Объедините свои силы

Избавьтесь от разбросанной по коду логики управления транзакциями, создав централизованную систему или репозиторий.

Глобальные изменения за раз: Подумайте, стоит ли это того

Перед внедрением глобальных перехватчиков хорошо подумайте: экономия на объеме кода может ослабить оптимизацию запросов.

Полезные материалы

  1. Понимание уровней изоляции транзакций в SQL Server — подробное описание влияния уровней изоляции на параллелизм в SQL Server.
  2. TransactionScope и управление транзакциями в Entity Framework — обсуждение применения TransactionScope для управления транзакциями.
  3. Оптимистическая параллельность и Entity Framework — различные стратегии управления параллельными конфликтами.
  4. Улучшение производительности Entity Framework и советы по оптимизации — полезные рекомендации по повышению эффективности использования EF.
  5. Теги запросов в EF Core — подробное рассмотрение возможностей тегов запросов в EF Core.
  6. Перехват SQL, сгенерированного Entity Framework — применение перехватчиков для логирования SQL-запросов.
  7. Оптимизация запросов Entity Framework с помощью Include — обзор методов оптимизации запросов в EF.