У меня есть ситуация, когда мое приложение создает динамический запрос LINQ с использованием PredicateBuilder на основе заданных пользователем критериев фильтра ( в стороне: посмотрите эту ссылку для лучшей реализации EF PredicateBuilder ),Проблема в том, что этот запрос обычно выполняется долго, и мне нужны результаты этого запроса для выполнения других запросов (т. Е. Объединения результатов с другими таблицами).Если бы я писал T-SQL, я бы поместил результаты первого запроса во временную таблицу или переменную таблицы, а затем написал бы другие мои запросы вокруг этого.Я думал о том, чтобы получить список идентификаторов (например, List<Int32> query1IDs
) из первого запроса, а затем сделать что-то вроде этого:
var query2 = DbContext.TableName.Where(x => query1IDs.Contains(x.ID))
Это будет работатьтеоретически;однако число идентификаторов в query1IDs
может быть в сотнях или тысячах (а выражение LINQ x => query1IDs.Contains(x.ID)
преобразуется в оператор T-SQL "IN", которыйплохо по понятным причинам), а число строк в TableName составляет миллионов .У кого-нибудь есть какие-либо предложения относительно лучшего способа справиться с такой ситуацией?
Редактировать 1: Дополнительные пояснения относительно того, что я делаю.
ХорошоЯ создаю свой первый запрос (query1), который просто содержит идентификаторы, которые меня интересуют. По сути, я собираюсь использовать query1 для «фильтрации» других таблиц.Примечание: я не использую ToList()
в конце оператора LINQ --- запрос выполняется , а не в настоящее время, и результаты no отправлено клиенту:
var query1 = DbContext.TableName1.Where(ComplexFilterLogic).Select(x => x.ID)
Затем я беру query1 и использую его для фильтрации другой таблицы (TableName2).Теперь я поставил ToList()
в конце этого оператора, потому что я хочу выполнить его и довести результаты до клиента:
var query2 = (from a in DbContext.TableName2 join b in query1 on a.ID equals b.ID select new { b.Column1, b.column2, b.column3,...,b.columnM }).ToList();
Затем я беру query1 и повторно использую его для фильтрации еще одной таблицы (TableName3), выполняю ее и передаю результаты клиенту:
var query3 = (from a in DbContext.TableName3 join b in query1 on a.ID equals b.ID select new { b.Column1, b.column2, b.column3,...,b.columnM }).ToList();
Я могу продолжать делать это для любого количества запросов:
var queryN = (from a in DbContext.TableNameN join b in query1 on a.ID equals b.ID select new { b.Column1, b.column2, b.column3,...,b.columnM }).ToList();
Проблема: запрос1 занимает долго время для выполнения.Когда я выполняю query2, query3 ... queryN, query1 выполняется (N-1) раз ... это не очень эффективный способ работы (особенно, если query1 не меняется).Как я уже говорил ранее, если бы я писал T-SQL, я бы поместил результат query1 во временную таблицу, а затем использовал эту таблицу в последующих запросах.
Edit 2:
Я собираюсь поблагодарить Альбина Суннанбо за ответ на этот вопрос за его комментарий:
Когда у меня возникли подобные проблемы с тяжелым запросом, который я хотел повторно использовать в нескольких другихзапросы Я всегда возвращался к решению создания объединения в каждом запросе и прикладывал больше усилий для оптимизации выполнения запроса (в основном путем настройки моих индексов).
Я думаю, что это действительно лучшее, что можно сделатьделать с Entity Framework.В конце концов, если производительность станет действительно плохой, я, вероятно, соглашаюсь с предложением Джона Вули:
Это может быть ситуация, когда переход к собственному ADO с сохраненным процессом возвращает несколько результатов и используетВнутренняя временная таблица может быть лучшим вариантом для этой операции.Используйте EF для остальных 90% вашего приложения.
Спасибо всем, кто прокомментировал этот пост ... Я ценю вклад каждого!