Программирование >>  Проектирование баз данных 

1 ... 63 64 65 [ 66 ] 67 68 69 ... 184


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

К сведению

Если решено хранить текущие данные отдельно от архивных, то нужно будет учесть случаи, когда необходимо запрашивать текущие и архивные данные вместе. Если это отдельные таблицы, то для совместного запроса к ним понадобится операция UNION ALL для двух отношений (таблиц). Если затем нам понадобится соединить это объединение с другими таблицами, то придется создать на базе его реальное или виртуальное представление. Тогда нам придется заплатить дорогую цену за разбиение данных, потому что при соединении с представлениями, содержащими объединение, возникает ряд серьезных проблем производительности. Здесь может помочь поддержка ручного секционирования, предусмотренная в версии 7.2, однако она действует только для таблиц с идентичными определениями столбцов.

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

При этом сразу же возникает вопрос: каким способом образовать эти данные? Разрешить ли пользователям непосредственно сопровождать текущую цену и с помощью триггера создавать действительную по дате запись из старого значения или же позволить им только изменять временные записи, используя триггер для обновления при необходимости текущей цены?

Мы рекомендуем следующее. Если текущее значение таково по определению (т.е. действительность по дате с ним не хранится), то его следует сопровождать непосредственно и выполнять каскадное распространение изменений в архивную таблицу с помощью триггеров. Саму архивную таблицу следует максимально защитить от прямых DML-операций, и для этого можно воспользоваться таким методом. В предыдущем разделе мы упоминали о том, что использование триггеров для предотвращения разрывов и перекрытий в действительных по дате таблицах сопряжено с трудностями, поскольку триггер должен запрашивать таблицу, которая запустила его, и эта таблица считается мутирующей. (Решение см. в приложении Б.) Однако в данном слугае можно обратить это в свою пользу - в частности, поместить триггер на архивную таблицу для обновления текущей цены. Если это срабатывает, мы выдаем ошибку, а если не срабатывает из-за того, что



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

При такой обработке следует осторожно обращаться с датами и временем и не создавать ни разрывов, ни перекрытий. Чтобы соблюсти абсолютную точность, нужно использовать глобальную переменную пакета, чтобы на каждом этапе обработке присутствовало одно и то же значение SYSDATE. Эту задачу можно существенно упростить, определив значение DATE FROM как дату, наступившую за секунду до ввода цены в действие, а значение DATE TO - как дату с точностью до секунды, когда эта цена перестанет действовать. При таком подходе значение DATE TO в одной записи будет равным DATE FROM в следующей по порядку записи, если нет разрывов по дате.

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

При логическом удалении строки, которые пользователь может считать удаленными, на самом деле не исчезают бесследно. Они могут быть удалены из живой таблицы, но останутся в архивных таблицах. При удалении временной диапазон в текущей архивной строке закрывается путем установки в DATE TO значения, равного SYSDATE. На как уничтожить все ссылки на строку из действительной по дате таблицы?

Допустим, пользователь ввел новый товар с ошибкой, на следующий день понял это и удалил введенную информацию. Наша триггерная логика вмешивается и создает в архивной таблице эпитафию ошибке, чтобы ее все видели! Хуже того, существует вероятность настоящей путаницы в отчетах о продажах, так как теперь получается, что товар существовал (и имел цену) в течение одного дня. Каждый, кто имеет опыт работы с финансовыми системами, знает, что ошибочно введенные данные всегда можно аннулировать, а не удалить, но в отделе маркетинга предполагают (довольно оправданно), что в отчетах не должны появляться несуществующие товары, и могут об этом забыть.

Ясно, гго в таких случаях нам может понадобиться отдельный набор функций для выполнения физических операций, с помощью которых можно исправлять ошибки, допущенные при вводе данных (или при других действиях). Ведь все мы делаем ошибки, не правда ли? Эти функции можно реализовать как набор хранимых процедур, инкапсулированных в пакет. Который в нашем случае будет манипулировать непосредственно таблицей архивных данных.

Примечание

, Необходимо также осознавать, что возможность производить физические ( операции над действительными по дате таблицами для исправления ошибок ввода является очень важной. Если слишком жестко контроли-! ровать действия пользователей, то в результате мы придем к ограничению о их полномочий. Как бы вежливо и дружелюбно ни вели себя вы и



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

Здесь важную роль может играть подход к проектированию приложения. Иногда полезно продемонстрировать пользователю, как работает механизм эффективности по дате. Например, можно отобразить на экране начальную и конечную даты, чтобы пользователь мог представить последствия того или иного действия. Системы, в которых попытались упростить пользователю задачу, скрыв действительные даты за кулисами , часто кажутся пользователям непонятными.

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

Как насчет внешних ключей?

в примере, который мы до сих пор рассматривали, у каждой записи о товаре имелся временной ряд цен. На рис. 7.1 показана более сложная модель, предназначенная для реализации скидок за объем заказа. Ее особенность в том, что и таблица PRICES, и таблица DISCOUNTS действительны по дате. Вспомним, что первичный ключ таблицы PRICES был определен как (PRODUCTCODE, DATETO). Следовательно, внещний ключ в таблице DISCOUNTS следует определить как пару столбцов F PRICE PROD-UCTCODE и FPRICEDATETO. Поскольку скидки тоже действительны по дате, то теперь мы имеем три столбца, описывающих действительность по дате, - F PRICE DATE TO, DATE TO и DATE FROM. В результате начинается большая путаница, особенно при переходе на следующий уровень, где в каждой строке у нас будет еще больше столбцов DATETO. Кроме того, написание SQL-запросов к структуре такого вида - занятие обременительное и сопровождающееся ошибками.

Можно с уверенностью сказать, что значения диапазона дат из таблицы DISCOUNTS должны попадать внутрь соответствующего диапазона дат из таблицы PRICES. Действительно, если цена начинает действовать с 1 января 1997 года, не имеет смысла вводить для нее скидку с 20 декабря 1996 года. Это всегда выполняется, если действительная по дате таблица является подчиненной таблицей другой действительной по дате таблицы.



1 ... 63 64 65 [ 66 ] 67 68 69 ... 184

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика