Как стать автором
Обновить

Комментарии 18

Откладывание проверки до commit — очень плохая практика для последующего переиспользования кода. Сложно будет делать массовые операции или подключать приложения, которые самостоятельно управляют транзакциями (exception в необычном месте).
И слишком громоздко для проверки "единственности" клерка в филиале. Если это просто пример одной проверки, а реальные проверки гораздо сложнее, то сойдет.
Если делаются только проверки, похожие на обычный constraint, то их конечно, лучше реализовывать с помощью constraint'ов. В данном примере — сделав денормализацию поля LOC (филиал) в таблице EMP и добавив проверку уникальности сочетания LOC, IS_CLERK. Плюс этого решения — крайняя простота (и сработает даже в Oracle 9i), минус — проблемы при массовых изменениях DEPT.LOC.
А я думал, что люди, пишущие бизнес логику в БД уже не существуют. Как вы с этим потом живете? Миграции, отсутствие нормальных средств тестирования. Я как-то видел базу в которой десятки тысяч строк кода. Это был ад.
---А я думал, что люди, пишущие бизнес логику в БД уже не существуют.

Мне приходилось видеть людей, которые загружали данные всей таблицы запросом select * from tbl, чтобы подсчитать количество строк или сумму значений по какому-то полю.

----отсутствие нормальных средств тестирования

юнит-тестирование логики не сильно отличается от других языков.

— Я как-то видел базу в которой десятки тысяч строк кода. Это был ад

Я бы сказал что это небольшая база, в SAP к примеру одних только таблиц десятки тысяч.
Мне приходилось видеть людей, которые загружали данные всей таблицы запросом select * from tbl, чтобы подсчитать количество строк или сумму значений по какому-то полю.

Юнцов хватает в любой сфере деятельности человека. Но здесь то речь идет о явно опытном специалисте. И он пишет правильные вещи, только на мой взгляд в не правильном месте. На сколько я понимаю текущие тенденции, все идет к тому, чтобы использовать БД в качестве массового хранилища данных с минимальным количеством логики внутри (обычно оставляют только минимальные constraint'ы) – это проще, лучше обслуживается, легче масштабируется.
юнит-тестирование логики не сильно отличается от других языков.

Я слабо верю в то, что тесты для моего кода на С# будут столь же затратны по времени как и тесты для SQL написаннные на SQL.
Я бы сказал что это небольшая база, в SAP к примеру одних только таблиц десятки тысяч.

Я писал о том, что в базе было много кода, а не много таблиц. Количеством таблиц меня не удивить. Меня пугает, когда эти таблицы живут своей жизнью, связаны кучей триггеров и используют сотни хранимых процедур для отработки какой-то логики внутри БД.
Обеспечивать полный ACID в коде промежуточного слоя весьма тяжело и затратно, особенно в больших многопользовательских распределенных системах, так не лучше ли делать то, что умеет RDBMS быстро и эффективно прямо там?
А транзакции и ограничения уникальности уже кто-то отменил? Или они не работают если их делать в коде на стороне службы, а не БД?
Вы вообще сложную бизнес-логику когда-нибудь встречали?
Попробуйте реализовать хотя бы ту задачу, что делал автор поста, сделать на апп.сервере с учетом многопользовательской системы и все сами поймете.
Я их уже не один десяток подобных проделал. Мне вполне хватает возможностей ORM для этих целей.
Три разных пользователя вставляют клерков в один отдел одновременн — ваши действия?
Слишком мало исходных данных. Ну допустим:

1. Все запросы обрабатывает центральная служба.
2. Все запросы службы к БД выполняются в одном потоке.
3. Тогда я перед вставкой клерка в БД считаю количество уже существующих клерков и не даю вставлять если их больше чем нужно.
4. Т.к. запросы сериализованы – первый пройдет, остальные обломятся.
Общие замечания.
Возраст реального комплекса полтора десятка лет — поэтому речь идет не столько о разработке космических кораблей сколько о ремонте и поддержке любимых велосипедов. Данные примера на которые накручен функционал в статье так-же соотносятся с реальными как соотносятся морская свинка и море )
Теперь серьезнее.
Предложение вынести бизнеслогику я бы сформулировал иначе. Смысл не в том в каком месте физически реализована бизнеслогика, а в том что бизнеслогика и функционал системной поддержи должны реализовываться в отдельных модулях. Эта попытка сделана (наверно несовременно) — вся бизнеслогика реализована в отдельной функции. Исполнитель поддерживающий эту функцию имеет очень поверхностные представления о системном слое вызова и отлаживает ее простым вызовом передав идентификатор экзэмляра проверяемой сущности. При этом текст с парой операторов в триггерах (по сравнению с текстом функции контроля) словом логика даже называть неудобно.
О массовых многострочных операциях.
При одном коммите "на нескольких миллионах строк" по десятку таблиц серверу с OLTP нагрузкой будет весело и без констрейнта.
Но говорят дбашникам никогда не надоедает смотреть на воду, огонь, кокуренцию на блокировках, и рост сегментов отката )
А когда надоедает они отключают констрейнт функцией var_chk.chk_on, которая в примере реализована как заглушка.
2teleavtomatika Предкомпилированый код PLSQL хранящийся на сервере вроде не самое плохое решение по производительности. Ошибаюсь? Серверов БД с… тысяч сток кода ну очень много — достаточно заглянуть в схемы SYSTEM и SYS.
2Ariant. Вас просто не понял. Предложите Ваше решение контроля информации одной строки по содержанию другой — выберем лучшее).
2sassy. Матвью не самоцель — инструмент. Цель-инициировать процесс котроля только по коммиту.
По VIEW и INSTEAD OF триггера — спасибо, посмотрю подумаю.
Извините повторюсь. Решение не идеально но оно реально работает.
Ну во-первых подход древний(кажется еще Кайт его описывал и уже тогда предлагал вариант получше — с mview log+fast refresh) и с кучей недостатков, например, в сложности зависимостей, громоздкости кода, которая провоцирует на трудноуловимые ошибки, ужасная производительность, но даже в этом древнем подходе такую тяжелую жесть обычно не создают. Учтите, что вы таким подходом фактически превращаете систему в однопользовательскую — два пользователя не смогут одновременно поменять хоть что-то у двух разных сотрудников в разных департаментах, т.к. их коммиты будут ждать друг друга из-за блокировок на MVIEW, да и кол-во генерируемого реду будет просто зашкаливать при мельчайших изменениях… И кстати, подход Кайта в вашем примере будет намного проще — просто fast refresh mview c count(*) по клеркам в разрезе департаментов с check constraint (cnt<=2).
Во-вторых, обычно в таких случаях предпочитают не такую размазанную и тяжелую логику с кучей слабых мест, а уменьшение точек входа — в идеале одной процедуры, которая вносит изменения и вызывает процедуры проверок бизнес-логики. Имхо главные правила — блокируй как можно меньше, не создавай бутылочных горлышек, и конечно принцип KISS/бритва Оккама ...
Ну во-первых подход древний(кажется еще Кайт его описывал и уже тогда предлагал вариант получше — с mview log+fast refresh)
Предложеный мною вариант не претендует на новизну. Скорее это пример практически реализованного на двух десятках серверов решения прошедшего годовую обкатку под нагрузкой OLTP до 300 коннектов и пока не приведшего к ужасам описаными Вами ниже.
Однако должен уточнить некоторые условия эксплуатации. Данный констрейнт по сути эмулирует для пакетного режима ввода интерактивный режим ввода через форму на клиенте. Форма толстого клиента именно так и работает — бизнеслогика зашитая в ней обеспечивает формирование на полях корректного набора данных и лиш потом позволяет запостить и закомитить данные на сервере. Реальная реализация констрейнта динамически включена только для сеансов пользователей под которыми работают внешние программные шлюзы (функция пакета chk_on). Для интерактивных сеансов толстого клиента триггера и матвьюха отдыхают а конкуренции на матвьюхе отсутствует.
Наверно в основном посте я сосредоточился на описании инструмента опустив технологию применения — похоже напрасно. Инструмент не претендует на всеобщую универсальность но свою задачу решает.
их коммиты будут ждать друг друга из-за блокировок на MVIEW — если включить констрейнт для всех сеансов — да, полностью согласен. Но поправимо. Поскольку блокировки ставятся построчно доработаем так, что бы каждый сеанс работал только со своими строками. Добавим в emp_chk и матвью два поля идентификаторов сеанса (sid/serial). Соответсвенно протянуть обработку этих полей во фразе where через все модули. Спасибо за идею )
И кстати, подход Кайта в вашем примере Извините. Смысл был в том чтоб описать архитектуру решения на простом примере. Вроде есть самосвал в который грузят ведро грунта для примера. В результате половина постов смотрят не на самосвал а на ведро грута и предлагают переделать самосвал в велосипед с прицепом потому как для ведра грунта достаточно велосипеда (извините за безобразное упрощенчество). Продолжаю повторять что с моей точки зрения решение легко масштабируется тк исходники триггеров 2х типов по сути являются шаблонами для установки которых на любую таблицу необходимы минимальные правки исходника. И если Вы таки встречали сложную бизнеслогику (см выше )) на форме то согласитесь что 200 строк из 4х шаблонов кода как плата за перенос ее из клиента на сервер не высока.
Создавать матвью только для проверки целостности данных довольно спорное решение. Если вопрос в изменении нескольких записей так сказать в бэк-енде, то лучше использовать VIEW и INSTEAD OF триггера над этими VIEW. Выполняете изменение одной записи в VIEW, а триггером правите сколько угодно записей в таблице (таблицах) за этой вью.
А такая матвью на нескольких миллионах строк будет создавать излишние накладные расходы при коммите.
Всетаки задача предложеного иструмента конкретна — допускать к фиксации только прошедшие бизнеслогику данные. Задача доопределять данные инициируя дополнительные DML не стоияла.
Похоже INSTEAD OF триггера работают по каждому DML по полям вьюхи — тогда возражаю. Функционал должен работать только по конечному набору данных.
Любой функционал приводит к расходам. Если функционал лишний — расходы тоже излишние.
Простите что так поздно вмешиваюсь, но вот реальная задача. Есть БД, есть набор из апп-серверов, одна фигня они разные, там несколько языков, объединяет их только общая бд.
И вот вопрос — куда в таком случае писать бизнесс-логику. Что бы не пилить бизнесс логику для каждого аппа и ловить все нестыковки с этим связанные, все же есть смысл вынести ее на сервер БД, бывают случаи, согласитесь.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации