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

Вид материалаДокументы

Содержание


Текущее состояние дел в сфере информатизации
План реорганизации
Новый отдел информационных систем
Основные цели системы
Текущие бизнес-процессы
Исследование потоков данных
Реляционный проект
Проектирование объектной базы данных
Описание схемы на языке ODL
Листинг 6.1. Описание на языке ODL схемы объектно-ориентированной базы для компании Mighty-Mite Motors
Системы управления
Подобный материал:
1   ...   12   13   14   15   16   17   18   19   ...   23

Текущее состояние дел в сфере информатизации


В информационной системе компании МММ функционируют разные компь­ютеры и приложения, при ее создании не было почти никакого планирования. Конструкторский отдел использует автономные рабочие станции САПР. Но, не­смотря на большие возможности САПР, записи об испытаниях анализируются вручную. В конструкторском отделе работают инженеры-проектировщики (неко­торые из них возглавляют проекты) и офисные служащие, но никто не отвечает за информационные системы. Попытки заставить офисных служащих создать про­стую базу данных для хранения информации о детях, испытывающих новые из­делия, а также результатах проверок с треском провалились. Стало ясно, что кон­структорскому отделу нужны профессионалы в области информационных систем. Хотя отдел готов принять на работу таких специалистов, руководство компании приняло решение заменить отдельные подразделения на централизованный от­дел информационных систем.

В производственном отделе находится автономный компьютер для учета за­купок и уровней запасов сырья, составления графика работы персонала, плани­рования работы сборочной линии и учета готовой продукции. Все эти приложе­ния были написаны на языке COBOL еще в начале 80-х годов, вскоре после того, как компания была образована. Данные, которыми занимается производствен­ный отдел, хранятся в файлах, которые недоступны другим приложениям. За об­работку информации отвечает штат из пяти сотрудников, большинство из кото­рых работают над сопровождением программ на COBOL. Хотя все они неплохие программисты, но базовые приложения перестали отвечать потребностям про­изводственного отдела, а руководство решило, что экономически невыгодно пе­реписывать их с нуля.

Отдел маркетинга и сбыта был автоматизирован только в 1987 году, и теперь там действует локальная вычислительная сеть (ЛВС), состоящая из одного сер­вера и 15 рабочих станций. Сервер обслуживает такие распределенные приложе­ния, как ввод текста и электронные таблицы. На нем же ведется база данных о маркетинге и сбыте, созданная с помощью dBase III Plus. Проблема состоит так­же в том, что ограничено количество одновременно работающих пользователей (не более 10) и есть сложности с обеспечением параллельного использования базы. Все это приводит к общей несогласованности сведений. База данных была разработана сотрудником группы информационных систем. Но этот программист уволился в 1992 году, а из оставшихся сотрудников никто не разбирается в напи­санной им программе. Сколько бы времени ни тратилось на сопровождение базы данных, проблема несогласованности остается.

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


План реорганизации

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

Новый отдел информационных систем

Первым шагом реорганизации является создание отдела информационных систем. Новый отдел фирмы вместе со всеми остальными будет размещаться в глав­ном офисе. Для этого компания планирует возвести к основному зданию при­стройку площадью 10000 кв. футов1.

Mighty-Mite Motors ищет кандидата на должность начальника, который бу­дет подотчетен непосредственно генеральному директору и станет курировать ре­организацию корпоративных компьютерных информационных систем.

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

Основные цели системы

Генеральный директор так определил цели, которые должны быть достигнуты в результате реорганизации:
  • разработать корпоративный план администрирования информации, в кото­
    ром будут документированы все базы данных компании. Документация долж­
    на содержать ER-диаграммы, схемы и словари данных;
  • создать план приложений, в котором будут отражены все прикладные про­граммы, необходимые для доступа к корпоративным базам данных;
  • сделать план-график ввода в эксплуатацию корпоративных баз данных
    и разработки прикладных программ;
  • подготовить спецификацию на закупки нового оборудования, необходимо­го для обеспечения доступа к базам данных как из штаб-квартиры, так и ди­станционно со стороны коммивояжеров. Хотя не каждому работнику будет разрешено обращаться ко всем базам данных, аппаратура должна обеспечи­вать максимально гибкий универсальный доступ с учетом будущего роста;
  • разработать и внедрить меры безопасности для ограничения доступа к кор­
    поративным базам данных;
  • установить базы данных и разработать прикладные программы;
  • закупить и установить необходимое оборудование.



Текущие бизнес-процессы

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

Процессы сбыта и сбора заказов

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

Каждый заказ оформляется на стандартном бланке заказа (см. рис. 6.2). Если заказ приходит по факсу, то он уже выглядит должным образом. Сведения о зака­зах, поступивших по телефону, вносятся вручную. Несколько раз в день служа­щий вводит заказы в базу данных, написанную на dBase III Plus. К сожалению, если в офисе отдела сбыта нет свободных людей, то ввод заказа откладывается. Это отрицательно сказывается на планировании загрузки сборочной линии и, ста­ло быть, на способности компании выполнять заказы в срок. Новая информаци­онная система призвана рационализировать процесс ввода данных, в том числе за счет электронной передачи заказов сотрудниками, находящимися в командиров­ке, и непосредственного поступления информации о заказах из офиса.

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

Процессы производства, учета и отгрузки

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

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



Рис. 6.2. Бланк заказа компании Mighty-Mite Motors

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

Таблица 6.1. Формат сводного отчета о заказах



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

Он же получает бланки заказов после того, как по ним был составлен сводный отчет. (Их ксерокопии хранятся также в отделе маркетинга и сбыта.) Бланки по­мещаются в картотеку в обратном хронологическом порядке, так что самый ран­ний заказ выполняется первым. Начальник склада сверяет указанное в заказе ко­личество с имеющемся на складе (табл. 6.2). Если он видит, что на складе достаточно готовых изделий, то заказ передается кладовщику. Если нет, заказ воз­вращается в картотеку для повторной проверки на следующий день. При такой системе заказы никогда не выполняются частично, так как отслеживать их было бы очень трудно. (Реорганизованная система должна уметь обрабатывать и час­тично выполненные заказы.)





Таблица 6.2. Отчет о наличии готовой продукции

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

Заказ сырья и комплектующих в компании МММ осуществляется по мере не­обходимости. Начальник производства ежедневно просматривает график загруз­ки сборочных линий (табл. 6.3) и текущие уровни запаса сырья (табл. 6.4) и реша­ет, что нужно заказать. Эта процедура в огромной степени зависит от знания, какое сырье и комплектующие нужны для производства каждого изделия. Гене­ральному директору такая ситуация очень не нравится, поскольку начальник про­изводства прекрасно справляется с планированием загрузки сборочных линий, но его оценки потребностей в сырье никуда не годятся. В результате производство приходится периодически останавливать из-за отсутствия исходных материалов. Поэтому генеральный директор хотел бы, чтобы процедура заказа сырья и ком­плектующих делалась автоматически. В новой информационной системе должны содержаться данные о том, какие исходные материалы необходимы для каждой модели. Базируясь на текущем графике загрузки сборочных линий и минималь­ном уровне запаса каждого вида сырья, она должна генерировать заказы по мере необходимости.

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

Испытания продукции

Высшее руководство компании Mighty-Mite Motors решает, какие модели за­пускать в производство, основываясь на данных из трех источников: результаты ис­пытаний, сведения о зарегистрированных клиентах и извещения о неисправностях.

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






Рис. 6.3. Регистрационная форма, заполняемая при покупке Таблица

6.4. Формат отчета о запасах сырья






Рис. 6.4. Извещение о неисправности




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

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

Результаты испытаний продукции фиксируются на бумажных бланках (см. рис. 6.5). Затем бланки вручную сортируются, и на их основе строится от­чет. Фирма хотела бы хранить указанные сведения в информационной системе и получать отчет автоматически, что сэкономило бы время и силы. Это помогло бы решить, какие модели запускать в производство.



Рис. 6.5. Отчет об испытаниях изделия

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

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

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

По отношению к базе данных задачи, стоящие перед компанией Mighty-Mite Motors, естественно разбиваются на следующие классы:
  • производство (включая учет готовой продукции и заказ сырья); а продажа игрушек магазинам и отгрузка заказанной продукции; а отчеты о покупках;
  • испытания;
  • обработка извещений о неисправностях.

Исследование потоков данных

В такой ситуации диаграмма потоков данных (ДПД) может оказать неоцени­мую помощь в выявлении тех мест, где с данными могут совместно работать раз­ные отделы компании. ДПД верхнего уровня (контекстная диаграмма), показан­ная на рис. 6.6, мало информативна. На ней лишь обозначено, что есть три внешних источника сведений: клиенты (магазины, которым компания продает свою продукцию), покупатели (люди, купившие игрушки в магазинах компании) и поставщики сырья. Тем или иным способом эта информация используется в об­щем процессе «Производство и сбыт продукции», что необходимо для функцио­нирования компании.

Однако ДПД первого уровня (см. рис. 6.7) гораздо более содержательна. По мере декомпозиции процессов обработки сведений определяются пять хранилищ данных:

Рис. 6.6. Контекстная ДПД для компании Mighty-Mite Motors

  • сырье - здесь хранятся сведения по учету сырья и заказам на сырье;
  • данные о продукции - это информация о характере производимых изделий
    и готовой продукции;



  • заказы клиентов - здесь содержатся данные о клиентах и заказы;



Рис. 6.7. ДПД первого уровня для компании Mighty-Mite Motors
  • данные о покупателях - сведения о физических лицах, купивших изделия
    компании, и о том, что именно продано;

а данные о неисправностях - тут хранятся отчеты о неисправностях.

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

а сведения о заказах клиентов требуются для сбыта и отгрузки;
  • данные о покупателях необходимы при регистрации покупателей и обработ­ке извещений о браке;
  • хранилище сведений о неисправностях используется только в процессе об­
    работки этой информации и является единственным, к которому не обра­щаются сразу несколько процессов.

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

ДПД помогла осознать, что имеется острая необходимость в интеграции раз­личных хранилищ данных. Кроме того, компания Mighty-Mite Motors сравни­тельно невелика, так что единая база данных, покрывающая все аспекты ее рабо­ты, вряд ли вырастет до невообразимых размеров. В конце концов, всегда можно распределить базу данных по нескольким серверам, физически приблизив различ­ные ее части к тем подразделениям, в которых соответствующие данные исполь­зуются наиболее интенсивно. При этом логический проект базы данных не изме­нится от того, выбрана ли централизованная или распределенная реализация. Принципиальное решение заключается в том, чтобы создать единую базу вместо конгломерата нескольких автономных, между которыми надо как-то организовы­вать обмен данными.

Реляционный проект

В проекте реляционной базы данных для компании Mighty-Mite Motors со­держатся следующие таблицы:

model (model numb. model_description, suggested_retail_price, shipping_weight, time_to_manufacture)

test (model numb, test date, test_location, test_code, test_results)

test_types (test code. test_description)

customers (customer numb. customer_name, customer_street, customer_city,

customer_state, customer_zip, contact_person, contact_phone,

contact_fax)

orders (order numb. customer_numb, order_date, order_total, order_filled) order_line (order numb, model numb. quantity_ordered, unit_price,

line_total, all_shipped)

shipments (order numb, model numb, shipplno date. quantity_shipped) product (serial numb. model_numb, date_manufactured, status_code,

order_numb, date_shipped)

product_status (status code. status_description) raw_material (material id numb. material_name, unit_of_measurement,

quantity_in_stock, reorder_point) supplier (supplier numb. supplier_name, supplier_street, supplier_city,

supplier_state, supplier_zip, supplier_contact, supplier_phone) material_order (do numb. supplier_numb, material_order_date,

material_order_total) material_order_line (po numb, material id numb. material_quantity,

material_cost_each, material_line_cost)

material_needed (model numb, material id numb. quantity_needed) manufacturing_line (line numb, line_status) line_schedule (line numb, production date. model_numb,

quantity_to_produce) owner (owner numb. owner_first_name, owner_last_name, owner_street,

owner_city, owner_state, owner_zip, owner_phone) purchase (serial numb. owner_numb, age, gender, purchase_date,

purchase_place, learn_code, relationship) purchase_feature (serial numb, feature code) learn_about (learn code. learn_description) feature (feature code. feature_description) problem_report (serial numb, problem date. problem_time,

problem_type_code, problem_description) problem_type (problem type code, problem_type_description)

Проектирование объектно-реляционной базы данных

Один из самых интересных аспектов внесения объектно-ориентированных воз­можностей в реляционную СУБД состоит в понимании того, выиграет ли в чем-нибудь данная схема от включения в нее объектов. Схема базы данных компании Mighty-Mite Motors не получает почти никаких плюсов от гибридного решения.

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

Лучшим применением объектной технологии к данной конкретной базе дан­ных было бы «обернуть» в объектную оболочку такие составные сущности, как адреса и номера телефонов. Подобные объекты можно было бы потом повторно использовать в разных местах базы данных, упростив тем самым форматирова­ние, поиск и прочую работу с ними.

Нет никакой специальной техники создания ER-диаграмм, адаптирован­ной к гибридным схемам. Поэтому здесь применяется немного модифициро­ванный UML. Точнее, атрибут, доменом которого является класс, присоединя­ется к этому классу пунктирной линией, стрелка которой направлена в сторону класса.

Примечание Во всех ER-диаграммах, встречающихся в главе, используется

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

Первая часть ER-диаграммы для гибридной схемы базы данных МММ изоб­ражена на рис. 6.8. На ней представлены три класса: LineCost (Стоимость строки заказа), Address (Адрес) и Phone (Телефон). Класс LineCost содержит число еди­ниц заказанного изделия и цену одного изделия. Некоторая операция класса вы­числяет и сохраняет итоговую стоимость по этой строке заказа.

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

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

Вторая часть гибридной ER-диаграммы для компании МММ изображена на рис. 6.9. Обратите внимание, что от сущности Customer2 отходят две линии, веду­щие к классу Phone. Это связано с тем, что атрибуты customer_phone и customer_f ах имеют один и тот же домен Phone. Все остальное на этой диаграмме в точности аналогично реляционному проекту.

На рис. 6.10 изображена последняя часть ER-диаграммы. По сравнению с ре­ляционным проектом наибольшему изменению подверглось отношение 0wner2. Теперь имя владельца - это объект класса Name, его адрес и телефон - объекты классов Address и Phone соответственно.



Рис. 6.8. Первая часть словаря сущностей и связей в объектно-реляционном проекте



Рис. 6.9. Вторая часть словаря сущностей и связей в объектно-реляционном проекте



Рис. 6.10. Третья часть словаря сущностей и связей в объектно-реляционном проекте

В результате получаются следующие отношения:

model (model numb, model_description, suggested_retail_price,

shipping_weight, time_to_manufacture)

test (model numb, test date, test_location, test_code, test_results) test_types (test code, test_description) customers (customer numb, customer_name, customer_address,

contact_person, contact_phone, contact_fax)

orders (order numb. customer_numb, order_date, order_total, order_filled) order_line (order numb, model numb. order_line_cost, all_shipped) shipments (order numb, model numb, shipping date, quantity_shipped) product (serial numb. model_numb, date_manufactured, status_code,

order_numb, date_shipped)

product_status (status code, status_description) raw_material (material id numb, material_name, unit_of_measurement,

quantity_in_stock, reorder_point) supplier (supplier numb. supplier_name, supplier_address,

supplier_contact, supplier_phone) material_order (do numb. supplier_numb, material_order_date,

material_order_total)

material_order_line (po numb, material id numb. material_line_cost) mater-ial_needed (model numb, material id numb, quantity_needed) manufacturing_line (line numb. line_status) line_schedule (line numb, production date. model_numb,

quantity_to_produce)

owner (owner numb. owner_name, owner_address, owner_phone) purchase (serial numb. owner_numb, age, gender, purchase_date,

purchase_place, learn_code, relationship) purchase_feature (serial numb, feature code) learn_about (learn code. learn_description) feature (feature code. feature_description) problem_report (serial numb, problem date. problem_time,

problem_type_code, problem_description) problem_type (problem type code, problem_type_description)

Сравнивая гибридный проект с традиционным реляционным, можно заме­тить, что первый компактнее. Поскольку несколько значений, таких, как состав­ные части адреса, теперь хранятся в одной колонке, проект стал немного проще. Так как выбраны достаточно распространенные классы, используемые в несколь­ких местах, код для выполнения часто встречающихся операций можно написать один раз и употреблять всюду, где нужно, что ускоряет разработку. Поэтому, хотя и не была использована ни одна из специализированных возможностей объектно-ориентированного проектирования, все же некоторое оправдание применению объектов имеется.

Главный недостаток, связанный с добавлением объектов в реляционную базу, состоит в том, что программисту нужно завершить их определение. Для создания реляционной схемы и манипулирования ею с помощью SQL не нужно иметь на­выков программирования. Но в гибридной схеме, чтобы дать пользователям воз­можность работать с объектами, программист должен написать код операций классов LineCost, Name, Address и Phone.


Проектирование объектной базы данных

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

ER-диаграмма

Первая часть ER-диаграммы изображена на рис. 6.11. На ней показаны типы атрибутов, поэтому сразу видно, какие классы используются как типы данных. Только в этом качестве применяются служебные классы, изображенные в прямо­угольниках с рамкой-тенью. Они не принимают участия ни в каких связях.

Примечание На этих ER-диаграммах есть все атрибуты классов, но пред-

ставлены лишь некоторые операции (из-за недостатка места). Полный перечень операций помещен ниже при рассмотрении за­писи данной схемы на языке ODL.

В отличие от реляционной базы данных, где признаком связи является нали­чие дополнительных парных атрибутов, в объектно-ориентированной базе нет эк­вивалента внешнего ключа. Поэтому может показаться, что в некоторых прямо­угольниках классов на ER-диаграмме чего-то недостает.

Рассмотрим, к примеру, класс MaterialNeeded (Необходимые материалы). На диаграмме присутствует только один атрибут - quantity_needed (Требуемое коли­чество). Если вы раньше имели дело с реляционными базами, то может возник­нуть вопрос: почему нет атрибутов material_id_numb (Идентификатор вида сырья) и model_numb (Номер модели)? Дело в том, что в ООБД хранятся идентификато­ры связанных объектов, а не объекты целиком и не их внешние ключи. Поэтому-то идентификаторы вида сырья и модели, определяющие необходимый материал, и не являются атрибутами класса MaterialNeeded. Вместо этого связь устанавли­вается отдельно с помощью языка ODL (или другого языка, используемого в кон­кретной ООСУБД).

Служебные классы трактуются по-другому. Если, например, класс Address выступает в роли типа данных атрибута, это означает, что в объемлющем объекте хранится сам объект класса Add ress. Другими словами, данные объекта Add ress как бы являются данными объемлющего объекта, а идентификатор объекта Address, напротив, не сохраняется.

В общем случае связь применяется тогда, когда хранение самих значений данных в объектах привело бы к ненужному дублированию, поскольку эта информация необходима в нескольких местах. Наоборот, класс используется как тип данных ат­рибута, если данные объекта этого класса должны трактоваться как данные объемлю­щего объекта и неприменимы ни к какому другому объекту. Можно сформулировать это и так: связи нужны для разделяемых данных, атрибуты - для неразделяемых.



Рис. 6.11. Первая часть ER-диаграммы для объектного проекта базы данных

На рис. 6.12 показана вторая часть объектно-ориентированной ER-диаграм-мы. Она содержит объекты, необходимые для работы с покупками изделий и с результатами испытаний. (Не забывайте, что эта база данных несколько отли­чается от обычно встречающихся на практике, поскольку компания отслеживает индивидуальные изделия по серийным номерам. Это аналогично единичному но­меру на автомобильных двигателях.)

С классом TestClass (Тест) связана небольшая проблема. Класс TestType (Тип теста) введен по двум причинам: он предоставляет справочник, содержащий на­звания испытаний для объектов класса TestClass, и упрощает доступ к результа­там испытаний по типу. Также существует отношение «многие-ко-многим» меж­ду классами ModelClass (Модель) и TestType. Может быть, класс TestClass должен быть композиционной сущностью?

Но на рис. 6.12 TestClass является обычной сущностью. Он независим от клас­са TestType, хотя на него и влияет класс ModelClass. (Невозможно иметь данные об испытании, если неизвестно, какая модель испытывается.) В данном случае то, что на первый взгляд представляется композиционной сущностью, - поскольку сводит связь «многие-ко-многим» к двум связям «один-ко-многим», - на самом деле является регулярной сущностью, которой есть соответствие в реальном мире.

Последняя часть ER-диаграммы изображена на рис. 6.13. Обратите внимание, что класс ProblemReport (Отчет о неисправности) похож на класс TestClass: он хотя и находится в середине связи «многие-ко-многим», но является тем не менее регуляр­ной сущностью, поскольку существует самостоятельно и находится в зависимости только от одного из своих родителей. Отчет о неисправности ProblemReport не зависит от типа неисправности ProblemType (Тип неисправности).

На рис. 6.13 представлены также непосредственные связи вида «многие-ко-многим»: связь между классами FeatureClass (Свойство) и ProductClass (Изделие) и между классами LearnAbout (Информация о...) и ProductClass. Выше говорилось о том, что непосредственные связи «многие-ко-многим» могут привести к потере информации. Но в данном случае это не составляет никакой проблемы, если толь­ко кто-нибудь не попытается применить эти связи к классам, расположенным выше в иерархии.

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

Есть два пути решения этой проблемы. Во-первых, прикладная программа может проверить все регистрации покупки изделия для определения номера мо­дели, а затем отобрать свойства на основании общих номеров моделей. Во-вто­рых, можно ввести в базу данных дополнительную связь - прямую связь «мно­гие-ко-многим» между классами FeatureClass и ModelClass.

При любом выборе дополнительно усложняется либо прикладная программа (что увеличивает время ее разработки), либо структура базы данных. Это отрица­тельная сторона наличия в базе прямых связей «многие-ко-многим». Если груп­пировка свойств по моделям используется часто, то, наверное, стоит пойти на



Рис. 6.12. Вторая часть ER-диаграммы для объектного проекта базы данных



Рис. 6.13. Третья часть ER-диаграммы для объектного проекта базы данных

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

Описание схемы на языке ODL

Описание объектно-ориентированной схемы базы данных на языке ODL при­ведено в конце главы (см. листинг 6.1). Оно полнее, чем ER-диаграммы, посколь­ку изображает больше операций. Заметьте, что в каждом классе есть методы чте­ния (get) и изменения (set). Каждый класс, находящийся на конце «один» некоторой связи (то есть в нем хранится множество идентификаторов связанных объектов), содержит также методы для вывода связанных данных.

Кроме того, во многих классах есть операции, требующие прохода вдоль од­ной или нескольких связей. Например, в классе ProductClass есть две операции: для получения информации о владельце изделия и нахождения сведений о моде­ли изделия. Та и другая возвращают идентификаторы объектов, так что с их по­мощью можно легко добраться до объекта-владельца и до объекта-модели.

Наконец, во многих классах есть операции для вставки и удаления значений из атрибутов связи. Знакомясь с ними, не забывайте, что поскольку для всех свя­зей объявлены также обратные отношения, то наличие операций вставки и удале­ния на каждом конце может оказаться излишним. Многие СУБД автоматически обновляют второй конец связи, если на первом был добавлен или удален иденти­фикатор объекта. Однако это зависит от реализации, так что вам нужно выяснить, как ведет себя в этом отношении ваша конкретная СУБД.

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

При изучении этих классов вспомните о навигационной природе ООБД. Как, на­пример, получить доступ к объекту класса PurchaseClass? У покупки нет уникального идентификатора. В действительности может существовать много объектов-поку­пок, сведения о которых в точности совпадают. Отличаются они только владель­цем, с которым связаны. Если проектировщик базы данных не назначил покупкам уникальный ключ, то добраться до них можно только из связанного объекта, будь то владелец или изделие. (Можно также получить доступ к объектам-покупкам из объектов классов FeatureClass и LearnAbout, но, принимая во внимание семантику этих связей, вы вряд ли захотите идти таким путем.)

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

Листинг 6.1. Описание на языке ODL схемы объектно-ориентированной базы для компании Mighty-Mite Motors

class ModelClass (extent AllModels)

{

attribute int nodel_numb; // Номер модели,

attribute string model_description; // Описание модели, attribute float suggested_retail_price; // Рекомендуемая цена, attribute float shipping_weight; // Погрузочный вес. attribute float time_to_manufacture; // Время изготовления, key model_numb; relationship set production_scheduled

inverse LineSchedule::which_model; relationship set materialised

inverse MaterialNeeded::model; relationship set orders_on

inverse OrderLine:: model; relationship set tests_performed

inverse TestClass::model; relationship set
products_made

inverse ProductClass::model; int getModelNumb(); string getModelDescription(); float getRetailPrice(); float getWeightO; float getTime();

void setModelNumb (in int iNumb); void setDescription (in string iDescription); void setWeight (in float iWeight); void setTime (in float iTime); void displayMaterialsUsed ()

raises (nojnaterial); void displayProductionSchedule ()

raises (not_scheduled); void displayOrdersFor ()

raises (no_orders); void displayTestsFor ()

raises (no_tests); void displayProductsInStock ()

raises (out_of_stock); void displayProductsPurchased ()

raises (no_purchases); void scheduleProduction (in Date iDate, in int iLineNumb,

in int iNumbToProduce);

void cancelProduction (in Date iDate, in int iLineNumb); void addMaterial (in int iMaterialNumb, in float iQuantity);


void removeMaterial (in int iMaterialNumb); void addProduct (in int iSerialNumb);

void addTest (in Date iDate, in string iLocation, in string iftesult); };

class ManufacturingLine {

attribute int line_numb; // Номер сборочной линии,

attribute string line_status; // Состояние линии, key line_numb; relationship set schedule_for

inverse LineSchedule::which_line; int getLineNumb(); string getStatus(); void setLineNumb (in int iNumb); void setStatus (in string iStatus); void displaySchedule (in Date iDate)

raises (no_schedule); void displaySchedule (in Date iStart, in Date iEnd)

raises (no_schedule); };

class LineSchedule {

attribute Date production_date;

attribute int quantity_to_produce;

relationship ModelClass which_model

inverse ModelClass::production_scheduled;

relationship ManufacturingLine which_line inverse ManufacturingLine::schedule_for;

Date getDateO;

int getQuantityO;

void setDate (in Date iDate);

void setQuantity (in int iOuantity); }

class RawMaterial (extent AllRawMaterials) {

attribute int material_id_numb; // Идентификатор материала.

attribute string material_name; // Название материала.

attribute string unit_of_measurement; // Единица измерения.

attribute float quantity_in_stock; // В наличии.

attribute float reorder_point; // Неснижаемый запас.

relationship set how_much_used inverse MaterialNeeded::rawjnaterial;

relationship set ordered_on inverse MaterialOrderLine::raw_material;

key material_id_numb;

int getNurab();

string getNarae();

string getUnit();

float getlnStockO;

float getReorderPoint();

void setNumb(in int iNumb);

void setName(in string iName);

void setUnit(in string iUnit);

void setInStock(in float iStock);

void setReorder(in float iReorder);

void decrementStock(in float iAmountUsed);

void incrementStock(in float iAmountAdded);

boolean needsReorderQ;

void displayModelsUsedln ()

raises (notUsed); void displayOutstandingOrders ()

raises (no_orders); set getSuppliers ()

raises (never_ordered); };

class MaterailNeeded

{

attribute float quantity_needed; // Нужное количество, relationship ModelClass model

inverse ModelClass::material_used; relationship RawMaterial rawjnaterial

inverse RawMaterial::how_much_used; float getQuantityO; void setQuantity (in float iQuantity); >;

class SupplierClass (extent AllSuppliers) {

attribute int supplier_numb; // Идентификатор поставщика.

attribute string supplier_name; // Название поставщика.

attribute Address supplier_address; // Адрес поставщика.

attribute Name supplier_contact_name; // Контактное лицо.

attribute Phone supplier_phone; // Телефон.

attribute Phone supplier_fax; // Факс.

key supplier_numb;

relationship set orders_placed_with inverse MaterialOrder::ordered_from;

int getSupplierNumb();

string getSupplierName();

Address getSupplierAddressO;

Name getContact();

Phone getVoicePhone();

Phone getFax();

void setSupplierNumb (in int iNumb);

void setSupplierName (in string iName);

void setAddress (in Address iAddress);

void setContact (in Name iContact);

void setPhone (in Phone iPhone);

void setFax (in Phone iFax);

void displayOrdersPlaced ()

raises (no_orders);

void addOrder(in Date iDate, in float iTotal); void deleteOrder (in int iNumb); };

class Address {

attribute string street;

attribute string city;

attribute string state;

attribute string zip;

string getStreet();

string getCityO;

string getState();

string getZipO;

void setStreet (in string iStreet);

void setCity (in string iCity);

void setState (in string iState);

void setZip (in string iZip);

string getLabel(); };

class MaterialOrder {

attribute int order_numb; // Номер заказа,

attribute Date material_order_date; // Дата заказа, attribute float material_order_total; // Сумма заказа, key order_numb; relationship Supplier ordered_from

inverse Supplier::orders_placed_with; relationship set items_on

inverse MaterialOrderLine::order; Date getOrderDateO; float getOrderTotal(); void setOrderDate (in Date iDate); void computeTotal ()

raises (no_line_items); void displayOrder ()

raises (no_line_items);


SupplierClass getSupplier();

void addltem (in int raw_material_numb);

void removeltem (in int raw_material_numb);

};

class MaterialOrderLine {

attribute LineCost material_line_cost; // Стоимость строки заказа, relationship MaterialOrder order

inverse MaterialOrder::items_on; relationship RawMaterial raw_material

inverse RawMaterial::ordered_on; LineCost getLineCost (); void setLineCost (in LineCost iCost);

};

class LineCost {

attribute float quantity_ordered; // Заказанное количество.

attribute float cost_each;

attribute float line_cost;

float getQuantityO;

float getCost();

float getLineCostO;

void setQuantity (in float iQuantity);

void setCost (in float iCost);

void computeLineCost ()

raises (missing_data); >;

class TestType (extent AllTestTypes) {

attribute int test_code; // Код испытания,

attribute string test_description; // Название испытания, relationship set tests_performed

inverse TestClass::type; int getCode(); string getDescription(); void setCoded (in int iCode); void setDescription (in string iDescription); void displayTestsPerformed ()

raises (no_tests); set find (in Date iDate);

raises (no_tests); set find (in Date iStart, in Date iEnd);

raises (no_tests); };

class TestClass {

attribute Date test_date; // Дата испытания.

attribute string test_location; // Место проведения испытания.

attribute.string test_results; // Результаты испытания.

relationship TestType type

inverse TestType::tests_performed;

relationship ModelClass model

inverse ModelClass::tests_performed;

Date getDateO;

string getLocation();

string getResultsO;

void setDate (in Date iDate);

void setLocation (in string iLocation);

void setResults (in string iResults); };

class CustomerClass (extent AllCustomers) {

attribute int customer_numb; // Номер клиента, attribute Name customer_name; // Название клиента, attribute Address customer_address; // Адрес клиента, attribute Phone customer_phone; // Телефон клиента, attribute Phone customer_fax; // Факс клиента, key customer_numb; relationship set orders_placed

inverse OrderClass::customer; int getNumb(); Name getName(); Address getAddressO: Phone getPhone(); Phone getFax(); void setNumb (in int iNumb); void setName (in int iName); void setAddress (in Address iAddress); void setPhone (in Phone iPhone); void setFax (in Phone iFax); set find () raises (no_orders); set find (in Date iDate)

raises (no_orders); set find (in Date iStart, in Date iEnd)

raises (no_orders):

void addOrder (in Date iDate in float iTotal); void deleteOrder (in int order_numb);

};

class Name {

attribute string first_name; // Имя.

attribute string last_name; // Фамилия.

attribute char middle_init; // Средний инициал.

string getFirstNameO;

string getLastName();

string getMiddlelnitO;

string getLastFirst ();

string getFirstLastO;

void setName (in string iFirst, in string iLast, in char iMidd raises (data_missing);

>;

class Phone {

attribute string area_code; // Код региона.

attribute string exchange; // Код коммутатора.

attribute string phone_number; // Номер телефона.

attribute string extension; // Добавочный.

string getPhoneO;

string getAreaCode();

string getExchangeO;

string getExtension();

void setAreaCode (in string iCode);

void setExchange(in string iExchange);

void setNumber(in string iNumber);

void setExtension(in string iExt); };

class OrderClass {

attribute int order_numb; // Номер заказа.

attribute Date order_date; // Сата заказа.

attribute float order_total; // Сумма заказа.

attribute boolean order_filled; // Заказ выполнен.

key order_numb;

relationship CustomerClass customer

inverse CustomerClass::orders_placed;

relationship set line_items inverse OrderLine;:order;

int getNumb();

Date getDate();

float getTotal();

boolean getFilled();

void setNumb (in int iNumb);


void setDate (in Date iDate); void computeTotal ()

raises (no_order_lines); void checkFilled()

raises (no_order_lines); set getLineltemsO

raises (no_order_lines);

void addLineltem (in int iModeNumb, in int iQuantity); void deleteLinelten (in int iModeNumb)

raises (no_on_order); };

class OrderLine {

attribute boolean all_shipped; // Все отгружено,

attribute LineCost line_cost; // Стоимость строки заказа,

relationship OrderClass order

inverse OrderClass::line_items; relationship ModelClass model

inverse ModelClass::orders_on; relationship set shipments

inverse ShipmentClass::order_line; relationship set
products_on

inverse ProductClass::order_line; boolean getShipped(); LineCost getLineCost (); void checkShipped()

raises (no_shipments); void setLineCost (in LineCost iCost)

raises (missing_data)

void addShipment (in Date iDate, in int iQuantity); void deleteShipment (in Date iDate)

raises (no_such_shipment); void addProduct (in int serial_numb)

raises (no_such_product); void removeProduct (in int serial_numb)

raises (not_on_shipment);
}; Г

class ShipmentClass {

attribute Date shipping_date; // Дата отгрузки.

attribute float quantity_shipped; // Отгруженное количество.

relationship OrderLine order_line inverse OrderLine: shipments;

Date getDate();

float getOuantity();

void setDate (in Date iDate); void setOuantity (in float iQuantity); };

class ProblemReport {

attribute Date problem_date; // Дата неисправности,

attribute Time problem_time; // Время неисправности,

attribute string problem_description; // Описание неисправности, relationship ProductClass product

inverse ProductClass::problem_with; relationship ProblemType type

inverse ProblemType::problems; int getDate(); int getTime(); string getDescription(); void setDate (in Date iDate); void setTime (in Date iTime); void setDescription (in string iDescription); void displayProblems ()

raises (no_problems); void displayProblems (in string iDescription)

raises (no_problems); void find (in Date iDate)

raises (no_problems); };

class ProductClass (extent AllProducts)

{

attribute int serial_numb; . // Серийный номер,
attribute Date date_manufactured; // Дата изготовления,
attribute Date date_shipped; // Дата отгрузки,

key serial_numb; relationship ModelClass model

inverse ModelClass::products_made; relationship ProductStatus status

inverse ProductStatus::products; relationship set
problems_with

inverse ProblemReport:'.product; relationship PurchaseClass purchase

inverse PurchaseClass::product; relationship OrderLine order_line

inverse OrderLine::products_on; int getSerialNumb(); Date getManufacturingDate(); Date getDateShipped(); void setSerialNumb (in int iNumb);


void setManufacturingDate(in Date iDate); void setDateShipped(in Date iDate); void displayProblems ()

raises (no_problems); OwnerClass getPurchaser ()

raises (not_purchased)i; ModelClass getModel(); PurchaseClass getPurchase

raises (not_purchased); };

class ProductStatus <

attribute int status_code; // Код статуса.

attribute string status_description; // Название статуса.

relationship set
products inverse ProductClass::status;

int getCodeO;

string getDescription();

void setCode (in int iCode);

void setDescription (in string iDescription);

void displayProducts ()

raises (no_products); };

class PurchaseClass (extent AllPurchases) {

attribute int age; // Возраст.

attribute char gender; // Пол.

attribute Date purchase_date; // Дата покупки.

attribute string purchase_place; // Место покупки.

attribute int relationship_to; // Отношение к владельцу.

relationship ProductClass product inverse ProductClass::purchase;

relationship set features inverse FeatureClass: purchases;

relationship set how_learned inverse LearnAbout: purchases;

relationship OwnerClass owner inverse OwnerClass: purchases;

int getAge();

char getGender();

Date getPurchaseDate();

string getPlace();

string getRelationship();

void setAge (in int iAge);

void setGender (in char iGender);







int getNumb();

Address getAddress();

Name getName();

Phone getPhone();

void setNumb (in int iNumb);

void setName (in string iName);

void setAddress (in Address iAddress);

void setPhone (in Phone iPhone);

void displayPurchases()

raises (no_purchases); void addPurchase(); void deletePurchase(); };


Системы управления

распределенными базами данных

В этой главе вы узнаете:
  • что такое система управления распределенной базой данных (СУРБД) и что представляют собой ее основные компоненты;
  • как уровень распределения данных и процессов влияет на реализацию БД;
  • как происходит управление транзакциями в среде распределенных баз данных;
  • как конфигурация распределенной базы данных влияет на процесс проектирова­ния БД.