Re[10]: Бизнес логика в ХП
От: Gattaka Россия  
Дата: 25.06.16 17:37
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, Gattaka, Вы писали:


G>>>>>>Таблицы User(Id, Name, Property), Network_Node(Id, Name, Property), User_User(User1Id, User2Id), Network_Node(Node1Id, Node2Id), UserOnNode(NodeId, UserId)

G>>Нет не правильно он говорит. У вас есть софт по администрированию сети. Суть софта выставлять вот такие вот признаки на узлах. Вы как администратор их периодически выставляете и снимаете у разных узлов.
G>>Я максимально упростил вам задачу. На самом деле это не булевый признак и т.д. и т.п.
G>Давай подробный сценарий с точки зрения пользователя.
G>Админ заходит, выбирает node, а дальше что?
Только вы учитывайте, что я вам из 140 таблиц и кучи бизнес-правил сделал упрощенный сценарий для простоты объяснения.
Итак, админ запускает приложение. Выбирает список узлов, правой кнопкой — назначить роль. Роль назначается на узлы, а также если на узле есть зарегестрированные пользователи (их может быть несколько, предположим что один) и если эти пользователи имеют связи между собой — нужно установить связи между сетевыми узлами, только если эти связи не были запрещены админом до этого, если нет запретов со стороны других ролей и эти связи еще не существуют. Плюс у связи может быть статус, но это опустим — нужно назначать в только для определенных статусов связей.
Роль это некоторое свойство узла. Их существует порядка 1000 ранзых.
Re[13]: Бизнес логика в ХП
От: Doc Россия http://andrey.moveax.ru
Дата: 25.06.16 17:41
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Тогда считайте, что у меня достаточный опыт и я говорю, что SQL всегда надо делать хорошо, а не "оптимизировать потом".


Теперь учтем что "хорошо" тоже субъективное понятие. Далее тоже все субъективно — каждый программист IMHO должен стараться делать хорошо, соблюдая при этом баланс качества решения и времени, затраченного на него. Тут скажется и опыт, и "соображалка" и т.д. А разница результатах, будет тем, что отличает новичка от специалиста (и их оплату).
Re[8]: Бизнес логика в ХП
От: Gattaka Россия  
Дата: 25.06.16 17:53
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>Здравствуйте, Gattaka, Вы писали:


G>>Это все здорово, но только разница между таким использованием ОРМ и написанием запросов на SQL сводится к тому какой язык мы используем. Ну по факту C#, т.к. многие не знают толком SQL. Суть ОРМ ведь не в этом. Идея такая, что мы работаем с нашими доменными объектами как обычно, будто базы данных нет. Эти доменные объекты содержакт в себе данные и методы по их обработке, бизнес логику. Если нужно я эти доменные сущности не только на сервере могу использовать, но и на клиенте, да где угодно. Т.к. они не зависят от БД, от ОРМ и чего бы то ни было еще.


Doc>А кто сказал что в хранилище должны храниться сущности BL именно в виде объектов BL? У нас есть DataAccess который возвращает объекты BL, а как там внутри DA — это проблемы DA.

Действительно, кто? Я не говорил... В БД может хранится как угодно, смысл ОРМ в том чтобы замепить доменную сущность на таблицу или таблицы не доставляя головной боли.

G>>А вот сохранение и вытаскивание объектов из БД берет на себя ОРМ и если она достаточна умная — все ок.


Doc>Ну вот тут не ясно. А как она должна догадаться что вы хотите только 2 поля из объекта. Вы как-то сами себя загоняете в круг "хочу чтобы ORM сама все вытаскивала — ORM плохая потому что вытаскивает все".

Вот собственно несостоятельность этой идеалистической картины я и пытаюсь донести. Причем идею работы с доменными объектами без привязки к БД я одобряю. Она здравая и интересная, но не реализованная еще...
И есть еще подход типа Dapper или linq2db — это вобще не ORM, это всего лишь способ писать на C# запросы к базе данных. Эдакий SQL без SQL... По мне так лучше сразу писать на SQL и не парится, к чему эта прослойка, которая лишь добавляет сложности, как правило не все умеет. Аргумент интеллисенс и упрощенного рефакторинга ИМХО того не оправдывает...
Re[11]: Бизнес логика в ХП
От: Dziman США http://github.com/Dziman
Дата: 25.06.16 18:26
Оценка:
Здравствуйте, Gattaka, Вы писали:

G> G>Давай подробный сценарий с точки зрения пользователя.

G> G>Админ заходит, выбирает node, а дальше что?

G> Только вы учитывайте, что я вам из 140 таблиц и кучи бизнес-правил сделал упрощенный сценарий для простоты объяснения.

G> Итак, админ запускает приложение. Выбирает список узлов, правой кнопкой — назначить роль. Роль назначается на узлы, а также если на узле есть зарегестрированные пользователи (их может быть несколько, предположим что один) и если эти пользователи имеют связи между собой — нужно установить связи между сетевыми узлами, только если эти связи не были запрещены админом до этого, если нет запретов со стороны других ролей и эти связи еще не существуют. Плюс у связи может быть статус, но это опустим — нужно назначать в только для определенных статусов связей.
G> Роль это некоторое свойство узла. Их существует порядка 1000 ранзых.

Пока звучит как бездумная денормализация.
avalon 1.0rc3 build 430, zlib 1.2.5
Re[9]: Бизнес логика в ХП
От: Doc Россия http://andrey.moveax.ru
Дата: 25.06.16 18:29
Оценка:
Здравствуйте, Gattaka, Вы писали:

Doc>>А кто сказал что в хранилище должны храниться сущности BL именно в виде объектов BL? У нас есть DataAccess который возвращает объекты BL, а как там внутри DA — это проблемы DA.

G>Действительно, кто? Я не говорил... В БД может хранится как угодно, смысл ОРМ в том чтобы замепить доменную сущность на таблицу или таблицы не доставляя головной боли.

А чем не угодили, например, анонимные типы?
Собственно, с точки зрения кода BL я не вижу разницы между запросом на LINQ и вызовом хранимки. В итоге вы получите некий объект с 2мя полями (или их массив). Что дальше? Куда вы поместите результат?

G>И есть еще подход типа Dapper или linq2db — это вобще не ORM, это всего лишь способ писать на C# запросы к базе данных. Эдакий SQL без SQL... По мне так лучше сразу писать на SQL и не парится, к чему эта прослойка, которая лишь добавляет сложности, как правило не все умеет. Аргумент интеллисенс и упрощенного рефакторинга ИМХО того не оправдывает...


Ну смотря кому и какой проект. Intellisense, рефакторинг, возможности написания относительно простых запросов C# программистом без привлечения SQL программиста, выше скорость разработки... Но разумеется все зависит от команды.
Re[12]: Бизнес логика в ХП
От: Gattaka Россия  
Дата: 25.06.16 19:19
Оценка:
Здравствуйте, Dziman, Вы писали:

D>Пока звучит как бездумная денормализация.

Ну я выше приводил уже список таблиц. Продублирую: "Таблицы User(Id, Name, Property), Network_Node(Id, Name, Property), User_User(User1Id, User2Id), Network_Node(Node1Id, Node2Id), UserOnNode(NodeId, UserId)"
Что здесь бездумно денормализовано и как бы вы нормализовали? Какой у вас получился бы список таблиц?
Re[10]: Бизнес логика в ХП
От: Gattaka Россия  
Дата: 25.06.16 19:26
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>А чем не угодили, например, анонимные типы?

А в рамках предметной области анонимные типы это что? Они по определению отсутсвуют в доменном языке.
Doc>Собственно, с точки зрения кода BL я не вижу разницы между запросом на LINQ и вызовом хранимки. В итоге вы получите некий объект с 2мя полями (или их массив). Что дальше? Куда вы поместите результат?
В доменный объект, я ведь доменными сущностями оперирую. Ровно как и заказчики с аналитиком.
Re[13]: Бизнес логика в ХП
От: Dziman США http://github.com/Dziman
Дата: 25.06.16 20:09
Оценка:
Здравствуйте, Gattaka, Вы писали:

G> D>Пока звучит как бездумная денормализация.


G> Ну я выше приводил уже список таблиц. Продублирую: "Таблицы User(Id, Name, Property), Network_Node(Id, Name, Property), User_User(User1Id, User2Id), Network_Node(Node1Id, Node2Id), UserOnNode(NodeId, UserId)"

G> Что здесь бездумно денормализовано и как бы вы нормализовали? Какой у вас получился бы список таблиц?

Начнем с того что в твоем описании фигурируют какие-то роли

Итак, админ запускает приложение. Выбирает список узлов, правой кнопкой — назначить роль. Роль назначается на узлы, а также если на узле есть зарегестрированные пользователи (их может быть несколько, предположим что один) и если эти пользователи имеют связи между собой — нужно установить связи между сетевыми узлами, только если эти связи не были запрещены админом до этого, если нет запретов со стороны других ролей и эти связи еще не существуют. Плюс у связи может быть статус, но это опустим — нужно назначать в только для определенных статусов связей.


Далее, property у нода и пользователя-это что за зверь? Для каждого свойства своя колонка? Они пересекаются между user, node? Как могут существать 2 таблицы Network_Node? Что такое User_User, UserOnNode(а почему тут вдруг отказались от underscore нейминга?)? А как запрещаются связи? И еще 100500 вопросов и потенциальных ответов на них из которых я сделал вывод что тут присутствует денормализация(вероятно не к месту) и как следствие попытки добиться консистентности данных через ХП.
avalon 1.0rc3 build 430, zlib 1.2.5
Re[11]: Бизнес логика в ХП
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.06.16 21:02
Оценка: +1
Здравствуйте, Gattaka, Вы писали:

G>Итак, админ запускает приложение. Выбирает список узлов, правой кнопкой — назначить роль. Роль назначается на узлы, а также если на узле есть зарегестрированные пользователи (их может быть несколько, предположим что один) и если эти пользователи имеют связи между собой — нужно установить связи между сетевыми узлами, только если эти связи не были запрещены админом до этого, если нет запретов со стороны других ролей и эти связи еще не существуют. Плюс у связи может быть статус, но это опустим — нужно назначать в только для определенных статусов связей.



Проблема в том, чтобы получить транзитивное замыкание? Тогда и процедура не сильно поможет. Лучше замыкание делать не в момент запроса, а строить заранее.
Re[11]: Бизнес логика в ХП
От: Doc Россия http://andrey.moveax.ru
Дата: 26.06.16 01:44
Оценка:
Здравствуйте, Gattaka, Вы писали:

Doc>>Собственно, с точки зрения кода BL я не вижу разницы между запросом на LINQ и вызовом хранимки. В итоге вы получите некий объект с 2мя полями (или их массив). Что дальше? Куда вы поместите результат?

G>В доменный объект, я ведь доменными сущностями оперирую. Ровно как и заказчики с аналитиком.

Т.е. на выходе у вас получаются объекты, у которых какие-то несколько свойств несут реальные значения, а остальные дефолтные? Мне кажется это неправильное состояние объекта.
Ведь как потом угадать что в свойстве лежит: реальное значение или дефолтное? Ну можно сделать флаги или ввести предопределённые значения вне диапазонов или сделать все свойства Nullable. Но ведь все это приведет к раздуванию кода BL еще больше, чем введение доп. сущностей.
Re[14]: Бизнес логика в ХП
От: Gattaka Россия  
Дата: 26.06.16 04:00
Оценка:
Здравствуйте, Dziman, Вы писали:

D>Здравствуйте, Gattaka, Вы писали:


G>> D>Пока звучит как бездумная денормализация.


G>> Ну я выше приводил уже список таблиц. Продублирую: "Таблицы User(Id, Name, Property), Network_Node(Id, Name, Property), User_User(User1Id, User2Id), Network_Node(Node1Id, Node2Id), UserOnNode(NodeId, UserId)"

G>> Что здесь бездумно денормализовано и как бы вы нормализовали? Какой у вас получился бы список таблиц?

D>Начнем с того что в твоем описании фигурируют какие-то роли

D>

Итак, админ запускает приложение. Выбирает список узлов, правой кнопкой — назначить роль. Роль назначается на узлы, а также если на узле есть зарегестрированные пользователи (их может быть несколько, предположим что один) и если эти пользователи имеют связи между собой — нужно установить связи между сетевыми узлами, только если эти связи не были запрещены админом до этого, если нет запретов со стороны других ролей и эти связи еще не существуют. Плюс у связи может быть статус, но это опустим — нужно назначать в только для определенных статусов связей.


D>Далее, property у нода и пользователя-это что за зверь? Для каждого свойства своя колонка? Они пересекаются между user, node? Как могут существать 2 таблицы Network_Node? Что такое User_User, UserOnNode(а почему тут вдруг отказались от underscore нейминга?)? А как запрещаются связи? И еще 100500 вопросов и потенциальных ответов на них из которых я сделал вывод что тут присутствует денормализация(вероятно не к месту) и как следствие попытки добиться консистентности данных через ХП.


Сначала я роли не вводил, ввел просто флаг property — считайте что это и есть роли. То есть свойство Property типа int и выставление туда значения — это есть назначение роли на узел. Таблицу User упростим до User(Id, Name).
Очевдно, что вторая таблица называется не Network_Node, а Node_Node. User_User — таблица связей пользователей, я не знаю а вы что подумали? Отказались от underscore нейминга потому что это нифига не важно сейчас. Мы ведь тестовую ситуацию разбираем.

Теперь еще раз что требуется сделать. Т.к. уже много раз переписывалось. В таблице User(Id, Name) 70000 записей. В таблице Network_Node(Id, Name, Property) 70000 записей. В Таблице UserOnNode(NodeId, UserId) — 70000 записей по одному пользователю на узле. В таблице User_User(User1Id, User2Id) — связи пользователей, все польователи связаны со всеми — это 70000*70000=4900000000 записей. На каждую из записей по 8 байт, т.е. приблизительно 36 гигабайт табличка, не учитывая индексов. Теперь в таблице Network_Node(Node1Id, Node2Id) — связи узлов. Допустим кто-то с кем-то уже был связан в случайном порядке 900000000 записей каких-то.
Нам нужно сделать: У узлов (35000 каких-то) Network_Node меняется свойство Property — бизнес логика такова, что нужно найти зарегестрированные на этих узлах пользовати и если они связаны — добавить связи по узлам.
На самом деле у связи тоже есть свойства, но давайте не будем сейчас усложнять. Вот задача просто такая как я выше описал сейчас.
Отредактировано 26.06.2016 4:06 Gattaka . Предыдущая версия .
Re[12]: Бизнес логика в ХП
От: Gattaka Россия  
Дата: 26.06.16 04:08
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, Gattaka, Вы писали:


G>>Итак, админ запускает приложение. Выбирает список узлов, правой кнопкой — назначить роль. Роль назначается на узлы, а также если на узле есть зарегестрированные пользователи (их может быть несколько, предположим что один) и если эти пользователи имеют связи между собой — нужно установить связи между сетевыми узлами, только если эти связи не были запрещены админом до этого, если нет запретов со стороны других ролей и эти связи еще не существуют. Плюс у связи может быть статус, но это опустим — нужно назначать в только для определенных статусов связей.



G>Проблема в том, чтобы получить транзитивное замыкание? Тогда и процедура не сильно поможет. Лучше замыкание делать не в момент запроса, а строить заранее.

Нет, я попробовал еще раз описать исходя из вопросов которые возникают: http://rsdn.ru/forum/design/6482289.1
Автор: Gattaka
Дата: 26.06.16

Проблема в том, что данных дофига — 36 ГБ и проекция вам не поможет.
Отредактировано 26.06.2016 4:13 Gattaka . Предыдущая версия .
Re[13]: Бизнес логика в ХП
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.06.16 09:02
Оценка: +4
Здравствуйте, Gattaka, Вы писали:

G>>Проблема в том, чтобы получить транзитивное замыкание? Тогда и процедура не сильно поможет. Лучше замыкание делать не в момент запроса, а строить заранее.

G>Нет, я попробовал еще раз описать исходя из вопросов которые возникают: http://rsdn.ru/forum/design/6482289.1
Автор: Gattaka
Дата: 26.06.16

G>Проблема в том, что данных дофига — 36 ГБ и проекция вам не поможет.

Проблема в том, что ты проблему не можешь объяснить, ты уже четвертый пост ходишь вокруг и даже запрос не привел и user flow объяснить не можешь нормально. У тебя есть только отмазка "данных много".
Re[2]: Бизнес логика в ХП
От: wildwind Россия  
Дата: 26.06.16 10:24
Оценка:
Здравствуйте, Artem Korneev, Вы писали:

G>>Так ли плохо реализовывать бизнес логику в высокопроизводительных хранимых процедурах?


AK>Мне однажды пришлось поддерживать такой проект.

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

А у тебя была возможность сравнить с таким же проектом, но с логикой на клиенте? Может там было бы еще хуже.

AK>Основная сложность поддержки того проекта была именно в хранимых процедурах, дело усугублялось тем, что процедуры писались профессиональным SQL-разработчиком, а поддерживалось это потом C# full-stack разработчиками, которым было непросто читать многостраничные cross-DB запросы с кучей JOIN'ов, CROSS-APPLY, MERGE и прочими прелестями.


Это не проблема подхода, это проблема управления проектом. Был профессиональный SQL-разработчик, потом на нем решили сэкономить. Вот и результат.
Re: Бизнес логика в ХП
От: wildwind Россия  
Дата: 26.06.16 10:35
Оценка: +2
Здравствуйте, Gattaka, Вы писали:

G>Так ли плохо реализовывать бизнес логику в высокопроизводительных хранимых процедурах? Либо сейчас модно использовать кодогенераторы типа ОРМ, которые генерируют ужасные sql запросы? Учитывая, что код на sql как правило более локаничный и лучше читается.


В общем виде я бы сказал так. Пока ваше приложение достаточно простое, некритичное к производительности и полностью владеет базой, используйте ORM. Но если систему планируется масштабировать (или просто возможностей ORMа перестанет хватать), нужно быть готовым перенести часть логики в хранимки. Хорошо бы, чтобы выбранный ORM это поддерживал. Причем нужно до последнего сопротивляться переносу именно бизнес логики, ограничиваясь логикой выборки и обработки данных.
Re[14]: Бизнес логика в ХП
От: Gattaka Россия  
Дата: 26.06.16 13:11
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, Gattaka, Вы писали:

G>>>Проблема в том, чтобы получить транзитивное замыкание? Тогда и процедура не сильно поможет. Лучше замыкание делать не в момент запроса, а строить заранее.
G>>Нет, я попробовал еще раз описать исходя из вопросов которые возникают: http://rsdn.ru/forum/design/6482289.1
Автор: Gattaka
Дата: 26.06.16

G>>Проблема в том, что данных дофига — 36 ГБ и проекция вам не поможет.

G>Проблема в том, что ты проблему не можешь объяснить, ты уже четвертый пост ходишь вокруг и даже запрос не привел и user flow объяснить не можешь нормально. У тебя есть только отмазка "данных много".

Ну раз так много человек плюсуют... Я вобще расчитывал что вы сами напишите этот запрос. Так было бы гораздо интереснее (тут без сарказма, действительно считаю что так было бы интереснее вам)
Вот запрос:


    -- 1. Простовляем списку узлов новую роль
        update Network_Node
    set Property = true -- Некий признак, флаг, роль и т.п. не вдаемся в подробности. Нам пока не важно.
    where Id in (select Id from @selectedNodes) --В хранимку приходит список идентификаторов выбранных пользователем узлов - табличная переменная @selectedNodes

    -- 2. В соответсвии с бизнес логикой нужно найти связать сетевые узлы, которым мы проставили роль по связям зарегестрированных на них пользователей 
    --    
    insert Node_Node(Node1Id, Node2Id)
    select distinct n.Id, un2.NodeId
    from Network_Node n
    join UserOnNode un1 on un1.NodeId = n.Id     -- Берем пользователей зарегестрированных на узле
        join User_User uu on uu.User1Id = un1.UserId -- Берем связи пользователя
        join UserOnNode un2 on un1.UserId = uu.User2Id -- Берем узлы на котором зарегестрирован связанный пользователь
    where n.Property = true 
          and not exists(select * from Node_Node nn3 where nn3.Node1Id = n.Id and nn3.Node2Id = un2.NodeId) -- такая связь еще не сущетвует


Итак, напомню

В таблице User(Id, Name) 70000 записей. В таблице Network_Node(Id, Name, Property) 70000 записей. В Таблице UserOnNode(NodeId, UserId) — 70000 записей по одному пользователю на узле. В таблице User_User(User1Id, User2Id) — связи пользователей, все польователи связаны со всеми — это 70000*70000=4900000000 записей. На каждую из записей по 8 байт, т.е. приблизительно 36 гигабайт табличка, не учитывая индексов. Теперь в таблице Network_Node(Node1Id, Node2Id) — связи узлов. Допустим кто-то с кем-то уже был связан в случайном порядке 900000000 записей каких-то.
Нам нужно сделать: У узлов (35000 каких-то) Network_Node меняется свойство Property — бизнес логика такова, что нужно найти зарегестрированные на этих узлах пользовати и если они связаны — добавить связи по узлам.

Re[15]: Бизнес логика в ХП
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.06.16 17:17
Оценка:
Здравствуйте, Gattaka, Вы писали:

G>Вот запрос:

  Запрос
G>

G>    -- 1. Простовляем списку узлов новую роль
G>        update Network_Node
G>    set Property = true -- Некий признак, флаг, роль и т.п. не вдаемся в подробности. Нам пока не важно.
G>    where Id in (select Id from @selectedNodes) --В хранимку приходит список идентификаторов выбранных пользователем узлов - табличная переменная @selectedNodes

G>    -- 2. В соответсвии с бизнес логикой нужно найти связать сетевые узлы, которым мы проставили роль по связям зарегестрированных на них пользователей 
G>    --    
G>    insert Node_Node(Node1Id, Node2Id)
G>    select distinct n.Id, un2.NodeId
G>    from Network_Node n
G>    join UserOnNode un1 on un1.NodeId = n.Id     -- Берем пользователей зарегестрированных на узле
G>        join User_User uu on uu.User1Id = un1.UserId -- Берем связи пользователя
G>        join UserOnNode un2 on un1.UserId = uu.User2Id -- Берем узлы на котором зарегестрирован связанный пользователь
G>    where n.Property = true 
G>          and not exists(select * from Node_Node nn3 where nn3.Node1Id = n.Id and nn3.Node2Id = un2.NodeId) -- такая связь еще не сущетвует

G>


Кстати в запросе ошибка, смотри третий джоин


G>Итак, напомню

G>

G>В таблице User(Id, Name) 70000 записей. В таблице Network_Node(Id, Name, Property) 70000 записей. В Таблице UserOnNode(NodeId, UserId) — 70000 записей по одному пользователю на узле. В таблице User_User(User1Id, User2Id) — связи пользователей, все польователи связаны со всеми — это 70000*70000=4900000000 записей. На каждую из записей по 8 байт, т.е. приблизительно 36 гигабайт табличка, не учитывая индексов. Теперь в таблице Network_Node(Node1Id, Node2Id) — связи узлов. Допустим кто-то с кем-то уже был связан в случайном порядке 900000000 записей каких-то.
G>Нам нужно сделать: У узлов (35000 каких-то) Network_Node меняется свойство Property — бизнес логика такова, что нужно найти зарегестрированные на этих узлах пользовати и если они связаны — добавить связи по узлам.


Если все пользователи связаны со всеми, то установка property на любом узле приведет к добавлению Node_Node всех узлов в поле Node2Id. Что для дальнейшего использования не имеет смысла, так как просто можно запрашивать n.Property вместо джоина к Node_Node.

А если ты приведешь реальные средние значения количества связей User_Node и User_User, то перемножив два числа получим количество считываемых\добавляемых строк. Например для User_Node примерное соотношение 10, а для User_User — 150, то надо будет получить максимум 1500 записей для каждого ID. Размер записи — 8 байт (два ID по 4 байта). То есть 12кб. Если это операция обновления, которая не выполняется 10 раз в секунду, то можно не беспокоиться о скорости.

А вообще я бы лучше сделал материализованную view вида

create view UserNodeJunction with schemabinding as 
select 
    un1.NodeId as Node1Id, 
    un1.UserId as User1Id, 
    un2.NodeId as Node2Id, 
    un2.UserId as User2Id 
from UserOnNode un1 
join User_User uu on uu.User1Id = un1.UserId -- Берем связи пользователя
join UserOnNode un2 on un2.UserId = uu.User2Id 


create clustered index PK_UserNodeJunction on UserNodeJunction (Node1Id, User1Id, Node2Id, User2Id)
create index IX_NodeLink on UserNodeJunction (Node1Id, Node2Id)


Тогда твой запрос вообще можно было бы во view превратить:
create view NodeWithProperty as 
select distinct n.Id, j.Node2Id
from Network_Node n
join UserNodeJunction j on n.Id = j.Node1Id
where n.Property = true


И если это view индексировать (вытащив distinct на уровень выше), то вовсе пропадет необходимость что-то куда-то вставлять.

ЗЫ. Тем не менее я понял твою идею — тяжелую логику держать на уровне SQL, а не тащит в приложение. И я с этим согласен. Но средства ты кардинально не те выбрал, как на уровне базы, так и на уровне приложения. Поэтому ничего толком обосновать не можешь.
Re[16]: Бизнес логика в ХП
От: Gattaka Россия  
Дата: 26.06.16 17:39
Оценка:
Здравствуйте, gandjustas, Вы писали:



G>Здравствуйте, Gattaka, Вы писали:


G>>Вот запрос:

G>
  Запрос
G>>

G>>    -- 1. Простовляем списку узлов новую роль
G>>        update Network_Node
G>>    set Property = true -- Некий признак, флаг, роль и т.п. не вдаемся в подробности. Нам пока не важно.
G>>    where Id in (select Id from @selectedNodes) --В хранимку приходит список идентификаторов выбранных пользователем узлов - табличная переменная @selectedNodes

G>>    -- 2. В соответсвии с бизнес логикой нужно найти связать сетевые узлы, которым мы проставили роль по связям зарегестрированных на них пользователей 
G>>    --    
G>>    insert Node_Node(Node1Id, Node2Id)
G>>    select distinct n.Id, un2.NodeId
G>>    from Network_Node n
G>>    join UserOnNode un1 on un1.NodeId = n.Id     -- Берем пользователей зарегестрированных на узле
G>>        join User_User uu on uu.User1Id = un1.UserId -- Берем связи пользователя
G>>        join UserOnNode un2 on un1.UserId = uu.User2Id -- Берем узлы на котором зарегестрирован связанный пользователь
G>>    where n.Property = true 
G>>          and not exists(select * from Node_Node nn3 where nn3.Node1Id = n.Id and nn3.Node2Id = un2.NodeId) -- такая связь еще не сущетвует

G>>


G>Кстати в запросе ошибка, смотри третий джоин



G>>Итак, напомню

G>>

G>>В таблице User(Id, Name) 70000 записей. В таблице Network_Node(Id, Name, Property) 70000 записей. В Таблице UserOnNode(NodeId, UserId) — 70000 записей по одному пользователю на узле. В таблице User_User(User1Id, User2Id) — связи пользователей, все польователи связаны со всеми — это 70000*70000=4900000000 записей. На каждую из записей по 8 байт, т.е. приблизительно 36 гигабайт табличка, не учитывая индексов. Теперь в таблице Network_Node(Node1Id, Node2Id) — связи узлов. Допустим кто-то с кем-то уже был связан в случайном порядке 900000000 записей каких-то.
G>>Нам нужно сделать: У узлов (35000 каких-то) Network_Node меняется свойство Property — бизнес логика такова, что нужно найти зарегестрированные на этих узлах пользовати и если они связаны — добавить связи по узлам.


G>Если все пользователи связаны со всеми, то установка property на любом узле приведет к добавлению Node_Node всех узлов в поле Node2Id. Что для дальнейшего использования не имеет смысла, так как просто можно запрашивать n.Property вместо джоина к Node_Node.


G>А если ты приведешь реальные средние значения количества связей User_Node и User_User, то перемножив два числа получим количество считываемых\добавляемых строк. Например для User_Node примерное соотношение 10, а для User_User — 150, то надо будет получить максимум 1500 записей для каждого ID. Размер записи — 8 байт (два ID по 4 байта). То есть 12кб. Если это операция обновления, которая не выполняется 10 раз в секунду, то можно не беспокоиться о скорости.

Считайте, что все со всеми минус 1000000 каких-то случайных связей между пользователями. Вот такие объемы. Те расчеты, что вы привели — оч. мало.

G>А вообще я бы лучше сделал материализованную view вида


G>
G>create view UserNodeJunction with schemabinding as 
G>select 
G>    un1.NodeId as Node1Id, 
G>    un1.UserId as User1Id, 
G>    un2.NodeId as Node2Id, 
G>    un2.UserId as User2Id 
G>from UserOnNode un1 
G>join User_User uu on uu.User1Id = un1.UserId -- Берем связи пользователя
G>join UserOnNode un2 on un2.UserId = uu.User2Id 

Ерунда :(, будет тормозить добавление и удаление связей.

G>create clustered index PK_UserNodeJunction on UserNodeJunction (Node1Id, User1Id, Node2Id, User2Id)
G>create index IX_NodeLink on UserNodeJunction (Node1Id, Node2Id)
G>


G>Тогда твой запрос вообще можно было бы во view превратить:

G>
G>create view NodeWithProperty as 
G>select distinct n.Id, j.Node2Id
G>from Network_Node n
G>join UserNodeJunction j on n.Id = j.Node1Id
G>where n.Property = true 
G>


Так джойн и так быстро делается, только при вставке связей вы получите дополнительные расходы. Плюс размер базы разратется в 2 раза. Если сейчас это 36 ГБ табличка — будет 72 ГБ.

G>И если это view индексировать (вытащив distinct на уровень выше), то вовсе пропадет необходимость что-то куда-то вставлять.


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

G>ЗЫ. Тем не менее я понял твою идею — тяжелую логику держать на уровне SQL, а не тащит в приложение. И я с этим согласен. Но средства ты кардинально не те выбрал, как на уровне базы, так и на уровне приложения. Поэтому ничего толком обосновать не можешь.

Ну супер! На самом деле я ожидал что вы dapper предложете или linq2db, но тоже не катит, т.к. работу с блокировками в многопользовательском режиме лучше возложить на SQL, в частности READPAST и т.п. подобные штуки понадобятся...
Отредактировано 26.06.2016 17:43 Gattaka . Предыдущая версия .
Re[2]: Бизнес логика в ХП
От: Gattaka Россия  
Дата: 26.06.16 17:50
Оценка: -2
Здравствуйте, Artem Korneev, Вы писали:

Проблема в том, что вы SQL толком не знаете. Я не собираюсь вам грубить или хамить... Но у большинства разработчиков делаются глаза круглыми при словах Table Spool, Nested Loop, кластерный и некластерный индекс чем отличаются. И не знание этих простых вещей не мешает им не только писать код под СУБД, но еще и хаять ее, что дескать "тормоза".
Re[2]: Бизнес логика в ХП
От: Gattaka Россия  
Дата: 26.06.16 17:52
Оценка:
Здравствуйте, Vladek, Вы писали:

Дело в другом, что ОРМ вам дает некотрые удобства по рефакторингу, но при этом много чего заберает. READPAST тот же как сделать? У СУБД куча возможностей и плюшек которые попросту обрезаются... Так может вобще отказаться от плюшек ОРМ?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.