powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Жуткий дизайн :(((
10 сообщений из 10, страница 1 из 1
Жуткий дизайн :(((
    #36192067
Фотография Relic Hunter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Hi,

Есть табличка платежных документов (ТПД) выплат по медстраховке. Расчет выплаты производится по массе параметров других таблиц на которые эта таблица ссылается, типа карточка клиента, план спонсора клиента, тип карточки (семейная, единоличная), таблица расценок за услуги и т.д. Данные в таблицах, на которые ссылается ТПД меняятся. Поскольку используется 3НФ при отркрытии ПД в разные момены времени форма ПД может показать различные данные, вытягиваемые по ссылкам. А этого быть не должно. Форма ПД должна выглядеть всегда одинаково, после рассчета выплаты. Делаем так сейчас. При изменении значений в ссылочных таблицах - старое значение сохраняется, при этом создается новая строка с новым значением. Получается значения как такового нет, а сеть их временные серии, оч старое, старое, текущее, может быть значение и в будущем.

Проблемы с таким дизайном:
1. SQL запросы получаются оч. тяжелыми и не всегда правильными (нет возможности обеспечения непересекаемости значений во времени).
2. GUI формы - тоже ужас. Вместо текстбоксов - везде датагрид. Пользователи ..уеют от таких экранов.

Кто-нибудь с таким дизайном сталкивался? Как разруливаете?

Спасибо!
...
Рейтинг: 0 / 0
Жуткий дизайн :(((
    #36192081
mcureenab
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Это не 3НФ, а ошибка проектирования.

В данном случае все данные, которые использовались в моемнт расчёта, и должны сохраняться, должны сохраняться в самой ТПД.

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

Если бы вы никогда не изменяли записи в исходных таблицах, временные связи сохранялись бы, и ваш подход был бы уместен (но не в плане нормализации БД, а в плане хранения повторяющихся данных). Но в данном случае это не так.
...
Рейтинг: 0 / 0
Жуткий дизайн :(((
    #36192089
Фотография Relic Hunter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я думал об этом - сохранять все в ПД. Но таких рассчетных значей сотни. Таблица ПД будет оч. быстро распухать. Еще момент - спонсор может попросить изненить план, скажем $1,000 -> $2,000 максимум, но конкретно с какой-то даты в будущем 01/10/2009, к примеру. Т.е. новый план мы не имеем права применять до указанной им даты и должны использовать старое значение $1,000 максимум Как быть?
...
Рейтинг: 0 / 0
Жуткий дизайн :(((
    #36192108
Фотография softwarer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Relic HunterПроблемы с таким дизайном:
1. SQL запросы получаются оч. тяжелыми и не всегда правильными
Не совсем понял, с чего вдруг. Итак, у нас есть временная серия, id_объекта, id_версии. Ключ таблицы - id_версии (не пара из двух). Тогда конкретные данные вытаскиваются простым и удобным запросом. Чтобы иметь возможность запрашивать "текущую версию", сажаем ещё поле с этим флагом, делаем индекс либо ключ на (id_объекта, флаг_текущей). Запрос тоже вполне простой.

Relic Hunter(нет возможности обеспечения непересекаемости значений во времени)
Повесьте ночной джоб примерно следующего характера:

Код: plaintext
1.
2.
3.
4.
5.
select d1.* ----> в почту DBA
from data d1, data d2 
where d1.id_объекта = d2.id_объекта 
and d1.id_записи <> d2.id_записи
and d1.date_start <= d2.date_finish
and d1.date_finish => d2.date_start

Relic Hunter2. GUI формы - тоже ужас. Вместо текстбоксов - везде датагрид. Пользователи ..уеют от таких экранов.
С какой стати? Или GUI нагенерён автоматически по таблицам?
...
Рейтинг: 0 / 0
Жуткий дизайн :(((
    #36192133
Фотография Relic Hunter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
softwarerRelic HunterПроблемы с таким дизайном:
1. SQL запросы получаются оч. тяжелыми и не всегда правильными
Не совсем понял, с чего вдруг.
А ставо... Если записи в по состоянию на текущий момент не окажется, нужно показывать запись из обозримого будущего, если таковые имеются. Если нет - из прошлого, и т.д. Вот пример (и так всегда)

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
Select b1."BENEFIT_KEY",b1."DIVISION_KEY",b1."DISCIPLINE_KEY",b1."BENEFIT_COVERAGE_DT",b1."BENEFIT_DESC",b1."BENEFIT_DEPEND_AGE1_NUM",b1."BENEFIT_DEPEND_AGE2_NUM",b1."HSA_SERVICE_DT_IND",b1."EFFECTIVE_ON",b1."EFFECTIVE_BY",b1."EXPIRED_ON",b1."EXPIRED_BY",b1."CREATED_ON",b1."CREATED_BY",b1."UPDATED_ON",b1."UPDATED_BY", 'C' Status From v_benefit b1
Where trunc(sysdate) between b1.effective_on and nvl(b1.expired_on, sysdate)                               
/* Futrue One */
Union All
Select b2."BENEFIT_KEY",b2."DIVISION_KEY",b2."DISCIPLINE_KEY",b2."BENEFIT_COVERAGE_DT",b2."BENEFIT_DESC",b2."BENEFIT_DEPEND_AGE1_NUM",b2."BENEFIT_DEPEND_AGE2_NUM",b2."HSA_SERVICE_DT_IND",b2."EFFECTIVE_ON",b2."EFFECTIVE_BY",b2."EXPIRED_ON",b2."EXPIRED_BY",b2."CREATED_ON",b2."CREATED_BY",b2."UPDATED_ON",b2."UPDATED_BY", 'F' Status From v_benefit b2
Where b2.effective_on =
    (select max(bn1.effective_on)
     from v_benefit bn1
     where bn1.DIVISION_KEY = b2.DIVISION_KEY
     and bn1.DISCIPLINE_KEY = b2.DISCIPLINE_KEY
    )
    and exists
    (select  1  from v_benefit bn2
     where bn2.DIVISION_KEY = b2.DIVISION_KEY
     and bn2.DISCIPLINE_KEY = b2.DISCIPLINE_KEY
     and bn2.effective_on >= Trunc(sysdate)
    )
    and not exists
    (select  1  from v_benefit bn3
     Where bn3.DIVISION_KEY = b2.DIVISION_KEY
       and bn3.DISCIPLINE_KEY = b2.DISCIPLINE_KEY
       and trunc(sysdate) between bn3.effective_on and nvl(bn3.expired_on, sysdate)
    )
/*Last Expired One */
Union All
Select b3."BENEFIT_KEY",b3."DIVISION_KEY",b3."DISCIPLINE_KEY",b3."BENEFIT_COVERAGE_DT",b3."BENEFIT_DESC",b3."BENEFIT_DEPEND_AGE1_NUM",b3."BENEFIT_DEPEND_AGE2_NUM",b3."HSA_SERVICE_DT_IND",b3."EFFECTIVE_ON",b3."EFFECTIVE_BY",b3."EXPIRED_ON",b3."EXPIRED_BY",b3."CREATED_ON",b3."CREATED_BY",b3."UPDATED_ON",b3."UPDATED_BY", 'T' Status From v_benefit b3
Where b3.effective_on =
    (select max(bn1.effective_on)
     from v_benefit bn1
     where bn1.DIVISION_KEY = b3.DIVISION_KEY
     and bn1.DISCIPLINE_KEY = b3.DISCIPLINE_KEY
    )
    and Not exists
    (select  1  from v_benefit bn2
     where bn2.DIVISION_KEY = b3.DIVISION_KEY
     and bn2.DISCIPLINE_KEY = b3.DISCIPLINE_KEY
     and bn2.effective_on >= Trunc(sysdate)
    )
    and not exists
    (select  1  from v_benefit bn3
     Where bn3.DIVISION_KEY = b3.DIVISION_KEY
       and bn3.DISCIPLINE_KEY = b3.DISCIPLINE_KEY
       and trunc(sysdate) between bn3.effective_on and nvl(bn3.expired_on, sysdate)
    )
softwarerRelic Hunter(нет возможности обеспечения непересекаемости значений во времени)
Повесьте ночной джоб примерно следующего характера:

Код: plaintext
1.
2.
3.
4.
5.
select d1.* ----> в почту DBA
from data d1, data d2 
where d1.id_объекта = d2.id_объекта 
and d1.id_записи <> d2.id_записи
and d1.date_start <= d2.date_finish
and d1.date_finish => d2.date_start
ДБА не знает какие данные должны быть. Так их забили туда. ДБА QA не хочет заниматься :)softwarer
Relic Hunter2. GUI формы - тоже ужас. Вместо текстбоксов - везде датагрид. Пользователи ..уеют от таких экранов.
С какой стати? Или GUI нагенерён автоматически по таблицам?
Нет, экраны построены вручную. Просто все значения на н их - временные серии, отображены гридами. Они требуют много места, да и юзеры их не воспринимают.
Приходится сортировать записи по их степени активности и поднимать текущие значения вверх.
Нет шоб одно значение показать в текстбоксе.
...
Рейтинг: 0 / 0
Жуткий дизайн :(((
    #36192217
mcureenab
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Relic HunterЯ думал об этом - сохранять все в ПД. Но таких рассчетных значей сотни. Таблица ПД будет оч. быстро распухать. Еще момент - спонсор может попросить изненить план, скажем $1,000 -> $2,000 максимум, но конкретно с какой-то даты в будущем 01/10/2009, к примеру. Т.е. новый план мы не имеем права применять до указанной им даты и должны использовать старое значение $1,000 максимум Как быть?

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

Храните в системе несколько планов с установленным периодом действия. В процессе расчёта ПД выбирайте нужный план, например в зависимости от даты ПД или сделки, или как положено вашими правилами. Ведь ни у кого не вызывает трудности работа на бумаге с текущим прейскурантом и с архивом прейскурантов и с проектом прейскуранта, который будет использоваться в будущем. И в системе не надо огород городить из гридов с разными версиями. Пользователь выбирает нужный план и видит только те записи, которые к нему относятся без всяких там версий.

В простом случае в час Ч из расчётной системы удаляется старый план и загружается новый.
...
Рейтинг: 0 / 0
Жуткий дизайн :(((
    #36192218
Фотография Relic Hunter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mcureenabВ простом случае в час Ч из расчётной системы удаляется старый план и загружается новый.Это как?
...
Рейтинг: 0 / 0
Жуткий дизайн :(((
    #36192754
mcureenab
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Relic Hunter,

не знаю подойдет ли это вам. у нас телефонный биллинг рассчитывает стоимость разговоров в реальном времени и его не интересует ни тариф который был до начала звонка, ни тариф который будет использоваться в будущем. Как только это будущее наступает, в биллинг из внешней системы загружаются новые тарифы, а старые удаляются. с этого момента звонки тарифицируются по новой цене. во внешней системе хранятся и архивные тарифы и действующие и проектируемые. но это всё разные тарифы, а не версии какого то тарифа прародителя, так пользователи избавляются от работы с версиями данных.
...
Рейтинг: 0 / 0
Жуткий дизайн :(((
    #36193151
SERG1257
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здравствуй история изменений aka slow changing dimensions type 2.
Сколько ж раз я ее реализовывал.
softwarer +1
softwarer Ключ таблицы - id_версии (не пара из двух)Плюс альтернативный ключ id_объекта+dto (dto лучше dfrom, так как последнюю версию запрашивают гораздо чаще)
Relic Hunter Если записи в по состоянию на текущий момент не окажется, нужно показывать запись из обозримого будущего, если таковые имеются. Если нет - из прошлого, и т.д. Вот пример (и так всегда)Вот чтобы на текущий момент запись всегда оказывалась нужен джоб + триггеры. Записи может не оказаться только на дату ранее dfrom

Relic Hunter ДБА не знает какие данные должны быть. Так их забили туда. ДБА QA не хочет заниматься :)DBA здесь просто пример. На самом деле это должен быть начальник бьющий по головам забивальщикам, обманщикам триггера. В идеале запрос должен быть пустым всегда.

Relic Hunter Нет шоб одно значение показать в текстбоксе.
На экране показывать одно значение - текущее на дату ПД (или на сегодня) Можно добавить кнопку - посмотреть историю изменений

Relic Hunter Я думал об этом - сохранять все в ПД.Нах нах. Если записи в справочниках не меняются (только протухают) и вставляется новая версия то достаточно ссылки на id версии либо ссылки на клиента + дату актуальности типа дата ПД (менее избыточно, меньше вероятность ошибится при смене даты ПД (не надо обновлять все ссылки), но более затратно).

Relic Hunter Т.е. новый план мы не имеем права применять до указанной им даты и должны использовать старое значение $1,000 максимум Как быть? Да все так же - в запросах всегда используется некая дата актуальности.

Код: plaintext
select * from client c where (some condition) and :date between dfrom and dto

Если dto - по настоящее время хранить не как null, а как дата в будущем '01-JAN-3000' (показывать клиенту ее можно как null) и добавить в индексы то работать будет совсем неплохо. Кроме того надо предусмотреть поведение системы на границе интервала, т.е. если dto предыдущей версии = dfrom текущей то вместо стильной :date between dfrom and dto придется писать dfrom<=:date and :date<dto то бишь упоминать :date (которое может быть хитрым выражением) дважды.
...
Рейтинг: 0 / 0
Жуткий дизайн :(((
    #36193315
mcureenab
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SERG1257если dto предыдущей версии = dfrom текущей то вместо стильной :date between dfrom and dto придется писать dfrom<=:date and :date<dto то бишь упоминать :date (которое может быть хитрым выражением) дважды.

Просто не надо допускать, чтобы границы соприкасались. Если дата определена с точностью до секунды, то достаточно для даты завершения версии принять дату начала следующей версии минус 1сек.

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

А вот идея хранить разные сущности в общих таблицах выглядит по меньшей мере странно.
...
Рейтинг: 0 / 0
10 сообщений из 10, страница 1 из 1
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Жуткий дизайн :(((
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]