Comments 23
Спасибо!
Возможно я чего-то не понимаю, но разве не правильнее получить уже сгруппированные данные из базы данных, чем получать массив данных и потом группировать его в памяти приложения?
Тем более что база данных по идее гораздо эффективнее выполняет такие действия.
Да и концептуально правильнее, насколько я знаю, работу с данными (агрегацию, сортировку сложные выборки) перекладывать как раз на базу данных — для того она и нужна.
А так получается что БД используется исключительно как обычное хранилище.
Так что мне кажется что первый вариант как раз лучше будет. ИМХО.
Тем более что база данных по идее гораздо эффективнее выполняет такие действия.
Да и концептуально правильнее, насколько я знаю, работу с данными (агрегацию, сортировку сложные выборки) перекладывать как раз на базу данных — для того она и нужна.
А так получается что БД используется исключительно как обычное хранилище.
Так что мне кажется что первый вариант как раз лучше будет. ИМХО.
Я тоже так сначала подумал и реализовал первый вариант. Но обратите внимание, что в приведенном примере ввиду отсутствия функций агрегации использование GROUP BY получается вырожденным: GROUP BY на стороне сервера ровным счетом ничего нам не дает. Так зачем тогда лишний раз напрягать базу?
На стороне сервера GROUP BY в первом случае и не происходит, он делает сортировку по CustomerId, чтобы на клиенте последовательно получить готовые данные, уже _сгруппированные_ по CustomerId.
Во втором случае Вы эту работу перекладываете на плечи managed кода, вместо того, чтобы просто позволить СУБД использовать индексы в
Во втором случае Вы эту работу перекладываете на плечи managed кода, вместо того, чтобы просто позволить СУБД использовать индексы в
ORDER BY `CustomerId`
Я неточно выразился. Да, Group By на стороне сервера не происходит, но вызов LINQ-метода GroupBy на стороне сервера серьезно усложняет запрос. Вопрос в том, насколько целесообразно это усложнение.
Сортировка? А так ли она нужна? Насколько я понимаю реализация GroupBy из LINQ To Objects просто перебирает список подряд. К тому же, если все сводить к сортировке, то можно во вторую реализацию добавить перед AsEnumerable() вызов OrderBy(o => o.CustomerId).
Похоже, без benchmark'а не обойтись. Сейчас попробую прогнать на 10кк записей.
Сортировка? А так ли она нужна? Насколько я понимаю реализация GroupBy из LINQ To Objects просто перебирает список подряд. К тому же, если все сводить к сортировке, то можно во вторую реализацию добавить перед AsEnumerable() вызов OrderBy(o => o.CustomerId).
Похоже, без benchmark'а не обойтись. Сейчас попробую прогнать на 10кк записей.
Итак. 1 миллион заказов, где CustomerId заполнен случайным образом в диапазоне от 1 до 1000 (то есть на каждый CustomerId приходится порядка 10к заказов). Сделал 3 замера (для 3, 5 и 10 CustomerId):
3 5 10
1. 7267 11532 19987
2. 5123 8685 17839
3. 5025 8950 17239
Единица измерения — милисекунды. 3-я реализация — вторая с добавленным OrderBy CustomerId (чтобы проверить влияние сортировки).
Насчет влияния сортировки (2 vs. 3). Дефолтная реализация GroupBy из Linq To Objects не получается выигрыша в производительности, если список элементов отсортирован. Так что разница между 2 и 3 реализация — скорее всего, просто погрешность. Другое дело, что можно было бы реализовать своей метод OrderGroupBy… но это уже совсем другая история.
3 5 10
1. 7267 11532 19987
2. 5123 8685 17839
3. 5025 8950 17239
Единица измерения — милисекунды. 3-я реализация — вторая с добавленным OrderBy CustomerId (чтобы проверить влияние сортировки).
Насчет влияния сортировки (2 vs. 3). Дефолтная реализация GroupBy из Linq To Objects не получается выигрыша в производительности, если список элементов отсортирован. Так что разница между 2 и 3 реализация — скорее всего, просто погрешность. Другое дело, что можно было бы реализовать своей метод OrderGroupBy… но это уже совсем другая история.
Определённо, если в базе убрать индексы, то второй способ победит =)
Коварно, ничего не скажешь.
Коварно, ничего не скажешь.
Скорее, наоборот, если хорошо настроены индексы, то при определенных условиях первая реализация приблизится по производительности ко второй.
Нука.
А если я сделаю 1 клиента, 1000000 заказов под ним и индекс по CustomerId.
На сколько порядков первая реализация отработает быстрее? =)
В общем, очень сильно зависит от данных. Но в общем случае, первый вариант лучше, потому что не несёт рисков как в примере выше.
А если я сделаю 1 клиента, 1000000 заказов под ним и индекс по CustomerId.
На сколько порядков первая реализация отработает быстрее? =)
В общем, очень сильно зависит от данных. Но в общем случае, первый вариант лучше, потому что не несёт рисков как в примере выше.
Вот в частности за это мне и нравится NHibernate. За то, что он даёт удобный способ написания старых-добрых SQL-запросов, а не предлагает некую «магию». Таким образом, когда пишешь сложный запрос к БД, задумываешься о том, как он будет выглядеть на SQL.
А в случае простых запросов — ну он такой же, как ЕФ :)
На NH пример выше выглядел бы как:
ну и SQL был бы в результате чуть-чуть оптимальнее:
а засунуть GroupBy-часть в SQL не было бы даже мысли, потому что sql-group-by здесь просто не нужен (он оставил бы из всех Заказов только один).
А в случае простых запросов — ну он такой же, как ЕФ :)
На NH пример выше выглядел бы как:
session.QueryOver<Order>()
.WhereRestrictionOn(x => x.Customer.Id).IsIn(customersIds)
.List().GroupBy(x => x.Customer.Id).ToDictionary(x => x.Key, x => x.ToList());
ну и SQL был бы в результате чуть-чуть оптимальнее:
SELECT * FROM orders WHERE order.customerId IN (1, 2, 3)
а засунуть GroupBy-часть в SQL не было бы даже мысли, потому что sql-group-by здесь просто не нужен (он оставил бы из всех Заказов только один).
Интересное разделение синтаксиса. Но в общем случае, думаю, я бы предпочел подход EF: LINQ прекрасен своим единообразием — не хочу изучать отдельный синтаксис LINQ под каждый ORM.
А насчет IN vs. Or — это нельзя рассматривать как преимущество NHibernate перед EF, это лишь преимущество провайдера под MySQL в NHibernate по сравнению с MySQL .NET Connector.
А насчет IN vs. Or — это нельзя рассматривать как преимущество NHibernate перед EF, это лишь преимущество провайдера под MySQL в NHibernate по сравнению с MySQL .NET Connector.
Мне четкие различия: где SQL, а где Linq, наоборот, нравятся. Нравятся четким представлением, что за запрос отправится в базу и угадыванием момента, когда пора оптимизировать.
Люди, хорошо знакомые с Linq, начнут писать запросы на EF быстрее, чем если бы они изучали NH. Тем, кто хорошо знаком с SQL, но мало — c Linq, наоборот будет проще стартовать с NH.
А когда знаешь и то, и другое — это на вкус и цвет :)
Ну и в принципе — обе системы неплохи, с этим не поспоришь.
Люди, хорошо знакомые с Linq, начнут писать запросы на EF быстрее, чем если бы они изучали NH. Тем, кто хорошо знаком с SQL, но мало — c Linq, наоборот будет проще стартовать с NH.
А когда знаешь и то, и другое — это на вкус и цвет :)
Ну и в принципе — обе системы неплохи, с этим не поспоришь.
Ваш вариант выглядел бы так для EF:
ctx.Orders
.Where(o => customersIds.Contains(o.Id))
.ToList()
.GroupBy(o => o.CustomerId).ToDictionary(o => o.Key, o => o.ToList());
И запрос он выдаст абсолютно такой же из-за .ToList()
ctx.Orders
.Where(o => customersIds.Contains(o.Id))
.ToList()
.GroupBy(o => o.CustomerId).ToDictionary(o => o.Key, o => o.ToList());
И запрос он выдаст абсолютно такой же из-за .ToList()
ну да, он и в посте так написан (за исключением AsEnumerable()).
Я просто хотел подчеркнуть, что при использовании NH не возникает желания вставить GroupBy «не туда», потому что NH заставляет задумываться о том, что идет в SQL, а что — в пост-обработку, не возникает смешения за счет одинаковости синтаксиса (как в EF).
При этом я не говорю, что это минус ЕФа, для многих единство синтаксиса как раз весомый плюс (как для автора, например, судя по комменту выше)
Я просто хотел подчеркнуть, что при использовании NH не возникает желания вставить GroupBy «не туда», потому что NH заставляет задумываться о том, что идет в SQL, а что — в пост-обработку, не возникает смешения за счет одинаковости синтаксиса (как в EF).
При этом я не говорю, что это минус ЕФа, для многих единство синтаксиса как раз весомый плюс (как для автора, например, судя по комменту выше)
какой у вас Linq To NHibernate провайдер?
А какая версия Linq to Entities?
Спасибо, полезно!
Sign up to leave a comment.
Linq To Entities vs. Linq To Objects на примере группировки