Какие есть способы оптимизации тяжелых запросов к базе данных
Что проверяют
Знаете ли вы, какой SQL на самом деле генерирует Entity Framework Core, и умеете ли его увидеть. Интервьюера интересуют практические приёмы: трекинг, проекции, Include, план выполнения в SQL Server. Следом часто спрашивают, когда вы уйдёте с EF на Dapper или чистый SQL.
Как отвечать
- увидеть запрос:
ToQueryString()наIQueryable, логирование черезLogToв настройках контекста, на стороне SQL Server Query Store и фактический план выполнения; - без трекинга для чтения:
AsNoTracking()убирает затраты на change tracker там, где сущности не будут меняться; - проекции:
Selectв DTO вытягивает только нужные колонки без материализации целых графов; Includeи декартов взрыв: несколькоIncludeпо коллекциям дают один запрос с перемноженными строками.AsSplitQuery()разбивает его на несколько запросов;- N+1: ленивая загрузка через прокси незаметно шлёт запрос на каждую строку в цикле;
- массовые изменения:
ExecuteUpdateиExecuteDelete(с EF Core 7) выполняются одним SQL-оператором без загрузки сущностей в память; - индексы: составные, покрывающие с
INCLUDE, фильтрованные. Представленияsys.dm_db_missing_index_*дают подсказки, но слепо применять их не стоит; - горячие пути: скомпилированные запросы
EF.CompileAsyncQuery, Dapper или сырой SQL черезFromSqlдля сложных отчётов; - кеш:
IMemoryCacheили распределённый кеш на Redis, а в экосистеме .NET 9 появилсяHybridCache.
Упомяните parameter sniffing: план, скомпилированный под первое значение параметра, бывает плохим для остальных. Лечится точечным OPTION (RECOMPILE) или пересмотром индексов.
Где спотыкаются
Называют SQL Server Profiler основным инструментом. Для движка базы он давно помечен устаревшим, актуальная замена Extended Events и Query Store.
Вызывают ToList() слишком рано и фильтруют уже в памяти через LINQ to Objects. Из базы уходит вся таблица.
Используют Contains по большому списку идентификаторов, не посмотрев SQL. В EF Core 8 для SQL Server список стал уходить одним JSON-параметром через OPENJSON, в следующих версиях трансляцию ещё меняли, поэтому проверяйте SQL на своей версии.