Pull to refresh

Comments 24

Я заранее извиняюсь, если чего-то не понимаю в Ораклах и прочих больших системах за многоденег, — но зачем эту задачу решать именно так? Тащить бизнес-логику в базу данных? Писать портянки кода на процедурном языке с кучей вложенных конструкций? Использовать паттерн EAV, который только ленивый ещё не пнул? Это же антипаттерн на антипаттерне.


Почему не сделать какой-нибудь NSIService со своим storage? Раз нужна версионность и история изменений — просто напрашивается Event Sourcing и CQRS...

Вы ошибаетесь, предложенная система вообще не зависит от бизнес-логике, а содержит голую структуру. И чем она будет наполнена зависит уже от разрабатываемой системы.
Что касается EAV, то я тоже не сторонник пихать его везде, где только можно, поэтому использую его для поддержания очень незначительной функциональности. При этом я не утверждаю, что такое решение самое-самое, это одно из возможных, кто-то может предложить другое исходя из потребности системы, которую он ведёт.
Хранилище, это замечательная идея, а если к ней добавить еще Event Sourcing и CQRS, то простынки кода на поддержание этой инфраструктуры будут никак не меньше, того, что здесь описано. И выгоды по критерию «многоденег» вряд ли удастся получить.
Любая система применима к определённым условиям, и то, что вы говорите, не есть альтернатива, а просто другая потребность. Когда есть необходимость создать хранилище, тогда стоит говорить каким образом это делать.
Где начинается бизнес-логика — вопрос философский… как мне кажется, если хранимая процедура/функция что-то знает о сущности предметной области (и пишется именно для organization, а не какого-нибудь для абстрактного nsi_item) — это уже в полный рост бизнес-логика. Впрочем, спорить не буду.

Что касается большего количества кода для написания отдельного сервиса с Event Sourcing / CQRS — безусловно, его будет больше. Но он будет лучше читаем, отлаживаем, тестируем, масштабируем, переносим, при необходимости может быть использован другими системами, которые не работают с этой БД, и т.д. и т.п.

При этом я догадываюсь, что вся эта предложенная мной красота может оказаться не подходящей в данном случае из-за каких-то критичных требований по производительности. О чём и был вопрос…
А в чём проблема относится к таблице nsi_organization, как к nsi_item? Я показала для примера, и совершенно не утверждаю, что такоё подход нужен исключительно только для систем, где необходимо работа с организациями, подставьте на это место другой справочник, структура от этого не поменяется.
И, кстати, у вас заказчик сильно идёт на внедрение новых технологий (я имею ввиду хранилище данных)? Если да, то вам повезло))))
Мне вообще легко — я с некоторых пор сам себе заказчик. И с похожими проблемами сталкиваюсь для себя. Причём тот же НСИ в части организаций — это весь ЕГРЮЛ на 2 с лишним миллиона записей, с перспективой подключения зарубежных реестров. Поэтому искренне любопытно, что даст (в отсутствие внешних ограничений и вводных на выбор технологий) именно такое решение и не надо ли мне начинать копить деньги на Оракл :)

А проблема, как мне кажется, в том, что Ваше решение и так ужé гвоздями приколочено к Ораклу, а при увеличении количества таблиц для разных типов НСИ эта зависимость будет только ухудшаться. В итоге при замене Оракла на другую БД надо переписывать не точечно один коннектор, а очень много чего в других местах. В общем, не layered architecture совсем получается. А ситуации разные бывают: деньги на Оракл закончились, под санкции попали и Оракл сам отказал в лицензии, принудительно вынудили импортозаместиться, да, в конце концов, понадобилось применить наработки в другом месте, где Ораклом и не пахнет…

Ну и да, писать процедурный код со вложенными циклами, когда вокруг только и говорят, что о красоте и эффективности функционального программирования, просто не доставляет удовлетворения :)
Ну если вы сами себе заказчик, тогда действительно легко))))
Начать копить на Оракле, чтобы доказать автору статьи, что его модель для вашего случая не подходит — сомнительная цель. Может быть начать с того, что определится чего вы хотите получить, а потом уже пытаться это решать. Я в статье обозначила это, а ваших комментариях я этого не вижу.
Помилуйте, я ничего не хочу никому доказать. Если бы я хотел поделиться своим опытом — я бы написал свою статью :) А комментарий я написал, чтобы получить знания, которых у меня нет.
И поскольку (а) в Вашей статье не содержалось обоснования, почему выбран именно Оракл и почему предложенный способ создания системы НСИ был реализован именно на хранимых функциях в нём, а (б) я не имею ни малейшего опыта работы с данной системой и (в) предложенный механизм показался мне сопряжённым со значительными ограничениями, — я и постарался уточнить причину такого выбора.
Если эта причина «Оракл уже был и корпоративная политика делать именно на нём» — ОК, это не мой случай. А если причина «так оно летает в 10 раз быстрее, чем если сделать на оперсорсных продуктах, сравнивали с такими-то и такими-то вариантами» — то про это действительно интересно узнать подробнее.
Думаю, вы сами себе ответили на вопрос. Если бы я хотела дать в статье сравнительную оценку быстродействия для различных серверов БД, то наверное бы так и поступила. Да и заголовок статья был бы тоже другой. Поэтому похоже, что вы заблудились в поисках недостающих знаний.
1. Никогда, ни за что, ни в коем случае не используйтё EAV для создания системы управления НСИ. Сразу вспоминается пара лет, убитых на то, чтобы уйти с такой модели данных, когда упёрлись в полное отсутствие масштабируемости такого решения, а оно было растиражировано в дюжину систем у множества заказчиков, уже работавших в проде.

2. Что за стремление использовать при проектировании системы, нагрузка на чтение в которой на 2-3 порядка выше, чем нагрузка на запись (а почти любая система управления НСИ такова), использовать структуры данных, оптимизированные для быстрой записи, но создающие абсолютно неадекватную нагрузку при чтении?

3. Использование конструкций вида
v_log_query := 'SELECT ''' || :NEW.surname || ''' AS surname, ''' || :NEW.name || ''' AS name, ''' || :NEW.patronymic || ''' AS patronymic, to_date(''' || :NEW.birthday || ''', ''dd.mm.yy'') AS birthday FROM DUAL'

для динамического SQL в Oracle это прям кровь из глаз и верный способ завалить собеседование и обратить на себя гнев DBA. Не надо так. Use bind variables, Luke!
1. Не обобщайте. EAV был предложен исключительно для атрибутов и не более.
2. А чем так сильно увеличилась нагрузка для выборки на чтение из таблицы организации (select * from nsi_organization)?
Модель данных Adjacency List для представления иерархии именно что оптимизирована на запись в ущерб чтению — простая и интуитивно понятная модификация иерархии, но построение иерархии из таблиц в такой модели данных требует рекурсивных запросов, которые изрядно грузят CPU.
Работа с иерархической структурой такая же необходимая вещь, как и с линейным списком. Практические все системы имеют такие справочники. И если вы создадите таблицу организаций, в которой укажите поле родителя, то вам тоже придётся для построения всех зависимостей обратиться к таблице деревянным запросом. И если для организаций глубина вложенности не будет особо большой (от силы порядка четырёх), то для построение структуры больших агрегатов, в которые включены более мелкие комплектующие, там глубина может исчисляться десятками.

Существуют различные способы упрощения жизни при работе с иерархией, например создать поле PATH, где будет храниться путь от корня и тогда выстроить запрос в линейный, использую оператор LIKE «1.23.%». Но это уже отдельная задача оптимизации работы с деревьями.
И если вы создадите таблицу организаций, в которой укажите поле родителя, то вам тоже придётся для построения всех зависимостей обратиться к таблице деревянным запросом

вы точно изучили теорию перед проектированием структуры данных? Nested sets и subsets не требуют рекурсивных запросов при построении, но да, сложнее в управлении и кодинге, чем наивное представление дерева через список смежности и уж точно эффективнее построения чего угодно с table access full и фильтрацией по строковому шаблону (тоже не самая дешёвая операция, между прочим).

Вообще статья вызвала ностальгию, вспомнилось хождение по граблям со справочниками в 2002-2008 годах. Пока что вы идёте ровно по тому же маршруту.
Вы только что подтвердили то, что написала во втором абзаце: «Существуют различные способы упрощения жизни при работе с иерархией...». Nested sets — один из таких способов.
Ну CQRS тут точно ни к селу, ни к городу. А код да, слабочитабельный. Legacy система, что тут скажешь. Автор крутится, как может, ищет выход из положения.
Тег Oracle18c не соответствует истине — весь код в стиле даже не 12 оракла, а в лучшем случае 11-го.

На мой взгляд, начало статьи сумбурное. Проблема описана с потерей информации о контексте.
Не могли бы вы более структурировано ответить на вопросы:
Какие требования предъявлялись к системе до и после изменений?
Какая была структура у таблиц до изменений? Какая получилась после?
Какие типичные запросы выполнялись в системе?
Запросы, которые вы написали это уже про "после"?


Из текста я нашел, что у вас были такие требования:


  • необходимо добавить ещё пару таблиц для нового оборудования и при этом все (включая старые) должны входить в определённую группу
  • оборудование имеет различные характеристики, более того их число переменно, а одна характеристика может иметь несколько значений
  • все справочники историчные (например, название продукта было одним, а потом его переименовали, и по документам на разные даты нужно показывать актуальное название)
  • справочники должны быть версионированы по изменениям

Судя по описанию, требования возникали не сразу, а постепенно. Было бы интересно узнать не просто результат, к которому вы пришли, а весь путь поэтапно.

Не совсем понимаю, что нужно уточнить. Потому как все ответы на вопросы есть в водной части статьи.
UFO just landed and posted this here
Прочитала вашу статью, никоим образом моя статья не входит в противоречие в вашей.
Хорошая статья, где описана работа по созданию хранилища данных.
Хочу заметить, что моя статья к хранилищу данных не имеет отношение, решается другая задача.
Почему вид НСИ вы вынесли в атрибуты? А не создали таблицу под каждый вид? В Вашем примере есть общий справочник в котором указывается вид НСИ.

Лучше же сделать НСИ под каждый вид НСИ. Пример Мета(вид)-child(Товары (одна таблица) -(ключ)- child Тип (другая таблица) и так далее.

Почему я спрашиваю, потому что нормальный запрос с большим объемом просто может положить ваши сервера) А так же это обязывает вас писать ключи к каждой merge.
Sign up to leave a comment.

Articles