Эффективный запрос данных с общими условиями - PullRequest
0 голосов
/ 16 ноября 2018

У меня есть несколько наборов данных, которые получены из контекста первого кода Entity Framework (SQL CE). Существует графический интерфейс, который отображает количество записей в каждом наборе запросов, и после изменения некоторого установленного условия (например, даты) все наборы должны пересчитать свое значение "count".

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

RelevantCustomers = People.Where(P=>P.Transactions.Where(T=>T.Date>SelectedDate).Count>0 && P.Type=="Customer")
RelevantSuppliers = People.Where(P=>P.Transactions.Where(T=>T.Date>SelectedDate).Count>0 && P.Type=="Supplier")

Так вот, этих требовательных запросов достаточно, так что каждый раз, когда пользователь меняет какое-либо условие (например, SelectedDate), требуется очень много времени для пересчета количества записей в каждом наборе.

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

Итак, мой вопрос заключается в том, что, учитывая, что эти наборы имеют общие "базовые условия", которые зависят от одних и тех же наборов данных, есть ли более эффективный способ расчета этих наборов?

Я думал о чем-то с пользовательскими родовыми классами, как это:

QueryGroup<People>(P=>P.Transactions.Where(T=>T.Date>SelectedDate).Count>0)
{
     new Query<People>("Customers", P=>P.Type=="Customer"),
     new Query<People>("Suppliers", P=>P.Type=="Supplier")
}

Я могу структурировать это очень хорошо, но я обнаружил, что в принципе это не имеет никакого значения для эффективности, поскольку все равно необходимо повторять «общее условие» для каждого набора.

Я также пытался сначала извлечь данные базового условия в виде статического «ToList ()», но это вызывает проблемы при работе с объектами навигации (т. Е. People.Addresses не загружаются).

Есть ли какой-то метод, о котором я не знаю, с точки зрения эффективности?

Заранее спасибо!

1 Ответ

0 голосов
/ 16 ноября 2018

Попробуйте что-то вроде этого: объедините «похожие» значения в меньшее количество запросов, а затем разделите результаты. Кроме того, используйте Any() вместо Count() для проверки существования. Ваша обновленная попытка идет частично, но все равно приведет к 2-кратным попаданиям в базу данных. Кроме того, при запросах это помогает гарантировать, что вы выполняете запросы к индексированным полям, и эти индексы будут более эффективными с числовыми идентификаторами, а не со строками. (То есть TypeID 1 против 2 для «Заказчик» против «Поставщик») Нормализованные значения лучше для индексации и приводят к меньшим записям за счет дополнительных подробных запросов.

var types = new string[] {"Customer", "Supplier"};
var people = People.Where(p => types.Contains(p.Type)
  && p.Transactions.Any(t => t.Date > selectedDate)).ToList();
var relevantCustomers = people.Where(p => p.Type == "Customer").ToList();
var relevantSuppliers = people.Where(p => p.Type == "Supplier").ToList();

Это приводит только к одному попаданию в базу данных, и Any должен быть более быстродействующим, чем выборка всего счета. Мы разделяем клиентов и поставщиков по факту из набора в памяти. Предостережение заключается в том, что любая попытка получить доступ к таким деталям, как транзакции и т. Д. Для клиентов и поставщиков, приведет к попаданию с отложенной загрузкой, поскольку мы не стремимся их загружать. Если вам нужны целые графы сущностей, убедитесь, что .Include () релевантные детали, или будьте более избирательными к данным, извлеченным из первого запроса. То есть выберите анонимные типы с соответствующими деталями, а не просто с сущностью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...