Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Жуткий дизайн :((( / 10 сообщений из 10, страница 1 из 1
11.09.2009, 21:47
    #36192067
Relic Hunter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Жуткий дизайн :(((
Hi,

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

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

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

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

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

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

Если бы вы никогда не изменяли записи в исходных таблицах, временные связи сохранялись бы, и ваш подход был бы уместен (но не в плане нормализации БД, а в плане хранения повторяющихся данных). Но в данном случае это не так.
...
Рейтинг: 0 / 0
11.09.2009, 22:18
    #36192089
Relic Hunter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Жуткий дизайн :(((
Я думал об этом - сохранять все в ПД. Но таких рассчетных значей сотни. Таблица ПД будет оч. быстро распухать. Еще момент - спонсор может попросить изненить план, скажем $1,000 -> $2,000 максимум, но конкретно с какой-то даты в будущем 01/10/2009, к примеру. Т.е. новый план мы не имеем права применять до указанной им даты и должны использовать старое значение $1,000 максимум Как быть?
...
Рейтинг: 0 / 0
11.09.2009, 22:39
    #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
11.09.2009, 23:24
    #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
12.09.2009, 04:11
    #36192217
mcureenab
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Жуткий дизайн :(((
Relic HunterЯ думал об этом - сохранять все в ПД. Но таких рассчетных значей сотни. Таблица ПД будет оч. быстро распухать. Еще момент - спонсор может попросить изненить план, скажем $1,000 -> $2,000 максимум, но конкретно с какой-то даты в будущем 01/10/2009, к примеру. Т.е. новый план мы не имеем права применять до указанной им даты и должны использовать старое значение $1,000 максимум Как быть?

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

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

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

не знаю подойдет ли это вам. у нас телефонный биллинг рассчитывает стоимость разговоров в реальном времени и его не интересует ни тариф который был до начала звонка, ни тариф который будет использоваться в будущем. Как только это будущее наступает, в биллинг из внешней системы загружаются новые тарифы, а старые удаляются. с этого момента звонки тарифицируются по новой цене. во внешней системе хранятся и архивные тарифы и действующие и проектируемые. но это всё разные тарифы, а не версии какого то тарифа прародителя, так пользователи избавляются от работы с версиями данных.
...
Рейтинг: 0 / 0
13.09.2009, 20:54
    #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
14.09.2009, 03:32
    #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]