Оптимизация SELECT запросов в Entity Framework 6: NOLOCK
Быстрый ответ
Для того чтобы внедрить поведение NOLOCK
в Entity Framework 6, вам нужно поместить свои запросы в контекст TransactionScope
с опцией IsolationLevel.ReadUncommitted
:
using (var scope = new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted }))
{
// Ваш запрос EF здесь будет выполнен с применением NOLOCK
var query = context.Entities.ToList();
// Обязательно выполните scope.Complete() для завершения транзакции.
scope.Complete();
}
Примечание: При применении NOLOCK
возможны грязные чтения. Поэтому использование этого подхода должно быть обдуманным.
Пользовательский перехват команд: Мастер маскировки
Для изменения SQL-команд без воздействия на базу данных вы можете использовать DbCommandInterceptor
.
Утончённое использование перехватчиков
Создайте собственный перехватчик, унаследовав его от DbCommandInterceptor
, и переопределите метод ReaderExecuting
, добавив подсказку NOLOCK
. Пример обработки:
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);
}
}
Зарегистрируйте перехватчик в методе инициализации вашего приложения:
DbInterception.Add(new NoLockInterceptor());
Обед не бесплатен
Применение NOLOCK
может значительно увеличить производительность, однако это сопряжено с риском грязного чтения данных. Это может привести к чтению данных, еще не законфирмированных транзакцией, или к пропуску определенных строк.
Управление транзакциями: Держите утят в ряд
Транзакции — это еще один способ работы с данными, позволяющий избежать побочных эффектов от NOLOCK
.
Применение TransactionScope
Управлять пакетными операциями предназначен TransactionScope
:
using (var transactionScope = new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions {
IsolationLevel = IsolationLevel.ReadUncommitted
}))
{
// Здесь применяются ваши операции с базой данных
transactionScope.Complete();
}
Создайте интерцептор уровня изоляции
Создайте IsolationLevelInterceptor
и добавьте его в конфигурацию EF DbConfiguration
:
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
можно сравнить с пользованием экспресс-кассой в супермаркете:
Без NOLOCK: [🛒🚶🛒🚶🛒🥫🍞🥛]
|----- Медленная очередь -----|
С NOLOCK: [🚀🛒💨]
|-- Экспресс-полоса --|
Entity Framework без NOLOCK
: вы находитесь в очереди за базовыми продуктами.
Entity Framework с NOLOCK
: вы проходите кассу быстро, но рискнуть пролить молоко (то есть столкнуться с проблемами с транзакциями).
Улучшение производительности: Предназначено для смельчаков
Попробуйте экспериментировать со следующими нестандартными методами улучшения производительности Entity Framework:
Профилирование и оптимизация: Покажите SQL, кто здесь главный
С помощью SQL Profiler вы можете наблюдать за эффективностью NOLOCK
и определить узкие места.
Повторное использование соединения: Делиться значит быть внимательным
Пользуйтесь пулом соединений SqlConnectionPool, чтобы оптимизировать использование ресурсов, снизив затраты на установление соединений.
Контроль времени жизни транзакции: Всё — дело времени
Для контроля над продолжительностью транзакций удобно использовать расширение DataReaderDisposing
в сценариях с IDataReader
.
Чистый и поддерживаемый код: Мы все любим порядок
Решения как UnitOfWork
и Repository
позволяют лаконично объединить логику управления транзакциями с перехватом команд.
Объедините свои силы
Избавьтесь от разбросанной по коду логики управления транзакциями, создав централизованную систему или репозиторий.
Глобальные изменения за раз: Подумайте, стоит ли это того
Перед внедрением глобальных перехватчиков хорошо подумайте: экономия на объеме кода может ослабить оптимизацию запросов.
Полезные материалы
- Понимание уровней изоляции транзакций в SQL Server — подробное описание влияния уровней изоляции на параллелизм в SQL Server.
- TransactionScope и управление транзакциями в Entity Framework — обсуждение применения
TransactionScope
для управления транзакциями. - Оптимистическая параллельность и Entity Framework — различные стратегии управления параллельными конфликтами.
- Улучшение производительности Entity Framework и советы по оптимизации — полезные рекомендации по повышению эффективности использования EF.
- Теги запросов в EF Core — подробное рассмотрение возможностей тегов запросов в EF Core.
- Перехват SQL, сгенерированного Entity Framework — применение перехватчиков для логирования SQL-запросов.
- Оптимизация запросов Entity Framework с помощью Include — обзор методов оптимизации запросов в EF.