Найти в Дзене
Архитектура на .NET

EF Core Query Splitting

EF Core при обращении к СУБД по умолчанию формирует один SQL-запрос для получения всех требуемых данных. Иногда это хорошо, т.к. позволяет доставать все необходимые данные одним запросом, а иногда это плохо, т.к. запрос может получиться слишком тяжелым из-за так называемого "комбинаторного взрыва". Как это происходит, рассмотрим подробнее на примере. Предположим, что у вас есть такой набор связанных сущностей: Каждому классу соответствует своя таблица в БД, а связи между ними обеспечиваются внешними ключами. Тогда, если вам нужно получить пользователя со всеми его заказами и их содержимым, ваш код будет выглядеть так: При выполнении этого кода EF Core сформирует примерно такой SQL-запрос (в действительности он будет несколько более сложным): Казалось бы, здесь всё хорошо, мы одним запросом получаем ровно то, что нам и требуется, и ничего лишнего. Но действительно ли это так? Сколько в итоге строк вернёт нам СУБД на этот запрос, и сколько в этом ответе будет лишних данных? Результат вы

EF Core при обращении к СУБД по умолчанию формирует один SQL-запрос для получения всех требуемых данных.

Иногда это хорошо, т.к. позволяет доставать все необходимые данные одним запросом, а иногда это плохо, т.к. запрос может получиться слишком тяжелым из-за так называемого "комбинаторного взрыва".

Как это происходит, рассмотрим подробнее на примере. Предположим, что у вас есть такой набор связанных сущностей:

Каждому классу соответствует своя таблица в БД, а связи между ними обеспечиваются внешними ключами. Тогда, если вам нужно получить пользователя со всеми его заказами и их содержимым, ваш код будет выглядеть так:

-2

При выполнении этого кода EF Core сформирует примерно такой SQL-запрос (в действительности он будет несколько более сложным):

-3

Казалось бы, здесь всё хорошо, мы одним запросом получаем ровно то, что нам и требуется, и ничего лишнего. Но действительно ли это так? Сколько в итоге строк вернёт нам СУБД на этот запрос, и сколько в этом ответе будет лишних данных?

Результат выполнения такого запроса приведен на картинке. На ней хорошо видно, что СУБД возвращает нам много повторяющихся значений, которые могут существенно замедлить выполнение обработки запроса.

-4

Чтобы избежать этого, можно использовать инструкцию AsSplitQuery():

-5

В этом случае SQL-запросов будет несколько, и дублирования в данных не будет. Имя пользователя и остальные его свойства будут возвращены ровно один раз. Статусы и даты создания заказов будут так же возвращены только один раз, по одной строке на заказ.