1000+ запросов Linq или логика в базе данных ... что хуже? - PullRequest
3 голосов
/ 24 июня 2010

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

Я должен принять решение о том, что отображать пользователя, основываясь на его назначении конкретному клиенту.Доменный объект выглядит как этот значительно упрощенный пример:

public class Customer
{
    public string Name { get; set; }
    public IEnumerable<Users> AssignedUsers { get; set; }
}

В реальном мире я также буду оценивать, имеют ли они разрешения (используя побитовые сравнения для флагов безопасности) для просмотра этого конкретного клиента.даже если они не назначены ему напрямую.

Я пытаюсь придерживаться принципов доменного проектирования (DDD).Также я использую LINQ to SQL для доступа к данным.На моем уровне обслуживания я предоставляю пользователю, запрашивающему список клиентов, который сейчас составляет около 1000 единиц и растет примерно на 2% в месяц.

Если я строго придерживаюсь логики в своем уровне обслуживания, янужно будет использовать Linq для выполнения .Where, который оценивает, содержит ли список AssignedUsers пользователя, запрашивающего этот список.Это вызовет каскад запросов для каждого Customer, когда система перечисляет до конца.Я не проводил никакого тестирования, но это кажется неэффективным.

Если бы я выдумал отсутствие логики в данных, то я мог бы просто иметь метод GetCustomersByUser(), который будет делать EXISTS тип SQL-запроса и оценки безопасности одновременно.Это, безусловно, будет намного быстрее, но сейчас я говорю о логике, попадающей в базу данных, которая может создать проблемы позже.

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

Ответы [ 6 ]

5 голосов
/ 24 июня 2010

Что хуже? Зависит от того, кого вы спрашиваете.

Возможно, если вы спросите ультра-пуриста DDD, они скажут, что логика в базе данных хуже.

Если вы спросите кого-то еще, ИМХО, особенно ваших конечных пользователей, прагматичных разработчиков и людей, которые платят за аппаратное обеспечение и разработку программного обеспечения, они, вероятно, скажут, что большой удар по производительности хуже.

У DDD есть много похвалы, как и у многих других подходов к проектированию, но они все падают, если вы упрямо следуете им до того, чтобы придумать «чистый» дизайн за счет соображения реального мира, такие как производительность.

Если вам действительно нужно выполнить такой запрос данных, то база данных почти наверняка далеко лучше при выполнении задачи.

В качестве альтернативы, вы "пропустили трюк" здесь. Ваш дизайн, однако DDD, на самом деле не так?

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

3 голосов
/ 24 июня 2010

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

С любой абстракцией вы будете получать накладные расходы в основном потому, что все просто не такэффективный, как вы или я, возможно, захотите их.MS проделала огромную работу, сделав LINQ достаточно эффективным.

Логика должна быть там, где она нужна. Чисто - это хорошо, но если вы предоставляете услугу или продукт, вы должны иметь в виду следующее (этобез конкретного заказа):

  1. Техническое обслуживание.Сможете ли вы легко выполнить работу после ее выпуска, не разбирая ее целиком на части.
  2. Масштабируемость.
  3. Производительность
  4. Удобство использования.

Номер 3 является одним из самых важных аспектов при работе с сетью.Вы бы сделали тригонометрию на SQL Server?Нет. Будете ли вы фильтровать результаты по входным параметрам?Да.

SQL Server создан для обработки больших запросов, фильтрации, сортировки и извлечения данных.Он процветает на этом, поэтому позвольте ему сделать это.

Это не логический крип, он помещает функциональность туда, где ему и положено.

1 голос
/ 24 июня 2010

Я думаю, что вашу модель лучше всего описать как отношение «многие ко многим» между классом Customer и классом User.Каждый пользователь ссылается на список связанных клиентов, а каждый клиент ссылается на список связанных пользователей.С точки зрения базы данных это выражается с помощью таблицы соединений (согласно терминологии Microsoft LINQ to SQL они называют это «таблицей соединений»).

Отношения «многие ко многим» - это единственная функция LINQ to SQLне поддерживает сразу из коробки, вы, вероятно, заметите это, если попытаетесь сгенерировать DBML.

Несколько блогов опубликовали обходные пути, в том числе один из MSDN (к сожалению, без конкретных примеров).Есть один блог (пост из двух частей), который строго соответствует предложению MSDN:

http://blogs.msdn.com/b/mitsu/archive/2007/06/21/how-to-implement-a-many-to-many-relationship-using-linq-to-sql.aspx

http://blogs.msdn.com/b/mitsu/archive/2008/03/19/how-to-implement-a-many-to-many-relationship-using-linq-to-sql-part-ii-add-remove-support.aspx

1 голос
/ 24 июня 2010

Если я строго придерживаюсь логики в своем слое обслуживания, мне нужно будет использовать Linq для выполнения. Где оценивается, содержит ли список AssignedUsers пользователя, запрашивающего список. Это приведет к каскаду запросов для каждого клиента, поскольку система перечисляет до этого. Я не проводил никаких испытаний, но это кажется неэффективным.

Не нужно перечислять локальную коллекцию клиентов.

Основная цель LinqToSql - позволить вам объявить логику на уровне обслуживания и выполнить эту логику на уровне данных.

int userId = CurrentUser.UserId;

IEnumerable<Customer> customerQuery =
  from c in dataContext.Customers
  where c.assignedUsers.Any(au => au.UserId = userId)
  select c;

List<Customer> result = customerQuery.ToList();
1 голос
/ 24 июня 2010

Если AssignedUser правильно сопоставлен (т. Е. Ассоциация сгенерирована дизайнером Linq2SQL или у вас есть свойство mark с AssosiationAttribute (или некоторым другим из пространства имен http://msdn.microsoft.com/en-us/library/system.data.linq.mapping(v=VS.90).aspx, я не уверен прямо сейчас), Linq2Sql переведет запрос linq в команду SQL, и не будет проходить через AssingedUser для каждого клиента.

Также вы можете использовать «обратный» запрос как

from c in Customer
join u in Users on c.CustomerId equals u.AssignedToCustomerId // or other condition links user to customer
where <you condition here>
select c
0 голосов
/ 24 июня 2010

Я бы лично пошел с сохраненным процессом. Это правильный инструмент для работы. Не использовать его может быть хорошим выбором дизайна, но парадигмы дизайна помогут вам, а не ограничат вас, по моему мнению. Кроме того, босс заботится только о производительности: -)

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