Informix ds/Universal Data Option - объектно-реляционная субд
Informix DS/Universal Data Option представляет собой реализацию объектно-ориентированной технологии на основе встраивания механизма абстрактных типов данных и механизма наследования в популярный и надежный сервер реляционных баз данных Informix Dynamic Server.
Встраиваемая объектно-ориентированная технология была известна на практике по объектно-реляционной СУБД Illustra (позднее, приобретеннной фирмой Informix и называвшейся Informix Illustra) [Stonebraker 96].
Определение новых базовых типов
Informix Universal Data Option позволяет вводить новые базовые типы данных. При этом можно использовать как встроенные в Informix Dynamic Server методы доступа и хранения, так и определять новые. Рассмотрим способ создания новых базовых типов с использованием встроенных механизмов хранения. Создание базовых типов вместе с алгоритмами хранения и доступа будет рассмотрено ниже.
Необходимость в создании новых базовых типов может возникать во многих случаях. Одним из самых простых случаев - это использование разных метрических систем для одного и того же понятия. Например, если некоторая фирма закупает детали в Америке, то их размеры будут указаны в футах, а цена в долларах, если аналогичные детали закупаются в Германии, то их размеры указываются в метрической системе, а цена в марках.
Если бы речь шла только про размеры, то алгоритм перевода размеров в единую систему измерений четко известен и в базе данных можно было бы хранить только размеры в метрах и сантиметрах. С ценами сложнее - курс обмена зависит от даты конвертации. И если мы будем искать деталь с минимальной ценой, то надо учитывать текущий курс. ОРСУБД Informix DS/Universal Data Option позволяет построить новый базовый тип данных, основанный на существующем, но обеспечивающий автоматическое преобразование к нужному значению. Сами типы вводятся следующими операторами:
CREATE DISTINCT TYPE usd AS MONEY; CREATE DISTINCT TYPE dm AS MONEY;
Далее надо ввести функции преобразования значений из долларов в марки и наоборот, а также описать возможность такого преобразования:
CREATE FUNCTION usd_to_dm(v usd) RETURNS dm; . . . CREATE FUNCTION dm_to_usd(v dm) RETURNS usd; . . .
CREATE IMPLICIT CAST (usd AS dm WITH usd_to_dm); CREATE IMPLICIT CAST (dm AS usd WITH dm_to_usd);
После этого можно сравнивать значения типов usd и dm, полученные из разных таблиц, не вызывая явно функцию преобразования. Такое решение существенно снижает возможность внесения ошибок, связанных с преобразованием значений.
Другой причиной, по которой может возникнуть необходимость во введении нового базового типа данных - это принципиальное отсутствие такого типа. Например, для экспериментальных данных, которые будут храниться в нашей базе данных, недостаточна точность, обеспечиваемая стандартным типом FLOAT. Informix DS/Universal Data Option позволяет ввести новый тип данных FLOAT16, будет использовать для хранения своих значений 16 байт и будет соответствовать нашим требованиям по числу значащих цифр в мантиссе и диапазону порядка:
CREATE OPAQUE TYPE float16 (INTERNALLENGTH=16, ALIGHNMENT=4);
Одного такого оператора недостаточно. Необходимо также задать функции преобразования значений данного вида в текстовый вид (тип данных LVARCHAR) и обратно (это нужно для ввода/вывода значений, экспорта/импорта базы и т.д.). Кроме того, нужно задать дополнительные функции преобразования и сравнения, которые будут использоваться при построении стандартных индексов и при сравнении со значениями других типов:
{обязательные функции преобразования в строку и обратно} CREATE FUNCTION float16_out(float16) RETURNING LVARCHAR . . . .; CREATE FUNCTION float16_in(lvarchar) RETURNING float16 . . . .;
{реализация стандартных операторов ’+’,’-’,’*’,’/’,’>’,’<’ и т.д.} CREATE FUNCTION Plus(float16, float16) RETURNING float16 . . . .; CREATE FUNCTION Plus(float16, float) RETURNING float16 . . . .; . . . . . . .
После того, как все нужные функции определены, можно использовать тип float16 наравне с другими базовыми типами (FLOAT, SMALLFLOAT, INTEGER и т.д.). При этом для хранения, поиска и индексирования используются стандартные механизмы Informix Dynamic Server.
Составные типы данных
Informix DS/Universal Data Option позволяет определять новые составные типы данных. К доступным структурам, которые можно использовать для построения составных типов, относятся:
запись
множество
список
Запись представляет собой возможность ввести именованные поля. Cтруктура запись структуре record в языке Паскаль и struct в языке C/C++. Тип данных со структурой запись вводится оператором:
CREATE ROW TYPE <имя типа> ( <имя поля> <тип поля>, . . . )
Например:
CREATE ROW TYPE fio_t ( last_name CHAR(40), {фамилия} first_name CHAR(40), {имя} second_name CHAR(40) {отчество} )
Cозданный таким образом составной тип может использоваться наравне и с предопределенными типами для описания колонок в отношении.
CREATE TABLE persons ( tabel_num INTEGER, {табельный номер} fio fio_t, {ФИО} . . . . . . )
Для доступа к отдельным полям внутри типа записи используется традиционный синтаксис - через точку надо указать имя поля:
SELECT tabel_num, fio.last_name, fio.first_name FROM persons WHERE tabel_num = 157
Множество представляет собой неупорядоченное множество значений. В Informix Universal Data Option используется два варианта реализации структуры множества - set и multiset. Первая структура (будем называть ее просто множеством) не допускает повторений элементов внутри себя. Вторая структура (будем называть ее мультимножеством) допускает повторение элементов. Приведем пример, как можно ввести в таблицу persons в качестве атрибута тип данных “дети” со структурой SET:
CREATE TYPE children_t SET ( fio fio_t, wasborn DATE )
CREATE TABLE persons ( tabel_num INTEGER, {табельный номер} fio fio_t, {ФИО} children children_t, {дети} . . . . . )
Список очень похож на мультимножество, но его элементы упорядочены. То есть в списке могут быть повторяющиеся значения, и эти значения можно перебирать по порядку. Рассмотрим реализацию типа со структурой “список” для хранения трудовой биографии (учреждение, дата приема, должность):
CREATE TYPE lab_byog_t LIST ( name CHAR(20), work_from DATETIME YEAR TO DAY, position CHAR(10) )
CREATE TABLE persons ( tabel_num INTEGER, {табельный номер} fio fio_t, {ФИО} children children_t, {дети} lab_byog lab_byog_t, {трудовая биография} . . . . . )
Наследование типов и данных
Пример, когда и инженеры, и администраторы, и продавцы с точки зрения работников отдела кадров выглядели совершенно одинаково, но по разному обрабатывались в бухгалтерии, очень удобно может быть реализован с использованием иерархии типов и данных.
Прежде всего, заметим, что имеется базовое понятие, сущность - сотрудник. Сотрудник характеризуется табельным номером, фамилией, именем, отчеством, должностью и окладом:
CREATE ROW TYPE employee_t ( tabel_num INTEGER, {табельный номер} last_name CHAR(40), {фамилия} first_name CHAR(40), {имя} second_name CHAR(40), {отчество} dolgnost CHAR(20) {должность} base_salary MONEY {оклад} )
В этом типе данных содержится вся информация, которая может быть интересна отделу кадров предприятия. Однако, как мы выяснили выше, для финансового отдела нужны дополнительные сведения. Для продавцов и инженеров дополнительно должна храиться и другая информация, необходимая для расчета зарплаты. Эту информацию можно учесть, создав типы engineer_t и sale_t как наследники типа employee_t:
CREATE ROW TYPE engineer_t ( bonus DECIMAL (5,2) {премия в процентах} ) UNDER TYPE employee_t
CREATE ROW TYPE sale_t ( comission DECIMAL (5,2), {размер комиссионных в %} revenue MONEY {сумма заключенных котрактов} ) UNDER TYPE employee_t
Таким образом, имеется 3 типа данных, два из которых (sales_t и engineer_t) являются наследниками одного (employee_t). Если мы используем эти типы для создания таблиц, мы можем создать иерархию данных:
CREATE TABLE employees OF TYPE employee_t; CREATE TABLE engineers OF TYPE engineer_t UNDER TABLE employees; CREATE TABLE sales OF TYPE sale_t UNDER TABLE employees;
В результате, мы имеем не три разных независимых таблицы, а одну главную таблицу (employees) и две наследованные таблицы (sales и engineers). Внимательный читатель может сказать, что ранее мы критиковали реализацию из трех таблиц как очень неудобную и ненадежную. Но в случае иерархии таблиц правильнее говорить об общей таблице и о двух ее подтаблицах. Каждая запись в наследованной таблице принадлежит и главной тоже (обратное неверно).
Таблица employees
Фамилия | Имя | Отчество | Должность | Оклад |
|
|
|
| |||||
Степанов | Степан | Степанович | админист. | 1700 |
|
|
|
| |||||
Кузьмин | Кузьма | Кузьмич | админист. | 1800 |
| Таблица Sales |
|
| |||||
|
|
|
|
|
| Комиссия (%) | Сумма сделок |
| |||||
Иванов | Иван | Иванович | продавец | 1000 |
| 0.5 | 500000 |
| |||||
Петров | Петр | Петрович | продавец | 1000 |
| 0.6 | 400000 |
| |||||
|
|
|
|
| Премия (%) | Таблица engineers |
| ||||||
Сидоров | Сидор | Сидорович | инженер | 1500 | 20 |
|
|
| |||||
Матвеев | Матвей | Матвеевич | инженер | 1600 | 20 |
|
|
|
В более сложных приложениях из таблиц (и соответсвующих им типов) можно организовывать и более сложные, многоуровневые иерархии.
Выборка данных по таблице employees даст возможность увидеть всех сотрудников:
SELECT * FROM employees
Фамилия | Имя | Отчество | Должность | Оклад |
Степанов | Степан | Степанович | админист. | 1700 |
Кузьмин | Кузьма | Кузьмич | админист. | 1800 |
Иванов | Иван | Иванович | продавец | 1000 |
Петров | Петр | Петрович | продавец | 1000 |
Сидоров | Сидор | Сидорович | инженер | 1500 |
Матвеев | Матвей | Матвеевич | инженер | 1600 |
Выборка данных по таблице engineers даст возможность увидеть всех инженеров, но только их, причем будут доступны и те поля, которые принадлежат типу engineer_t, но не принадлежат типу-родителю employee_t:
SELECT * FROM engineers
Фамилия | Имя | Отчество | Должность | Оклад | Премия (%) |
Сидоров | Сидор | Сидорович | инженер | 1500 | 20 |
Матвеев | Матвей | Матвеевич | инженер | 1600 | 20 |
Из таблицы employees можно выбрать и записи, которые принадлежат только этой таблице, и не входят в наслеованные. Для этого используется ключевое слово ONLY:
SELECT * FROM ONLY(employees)
Фамилия | Имя | Отчество | Должность | Оклад |
Степанов | Степан | Степанович | админист. | 1700 |
Кузьмин | Кузьма | Кузьмич | админист. | 1800 |
Имея иерархическую структуру таблиц, можно ввести функции расчета зарплаты, которая будет учитывать специфику каждого конкретного сотрудника. Это называется позднее связывание - какая конкретная функция будет применяться динамически определдяется на этапе исполнения в зависимости от того, какой таблице в иерархии принадлежит та или иная запись:
CREATE FUNCTION zarplata(p employee_t) RETURNING MONEY; RETURN (p.base_salary);
CREATE FUNCTION zarplata(p engineer_t) RETURNING MONEY; RETURN (p.base_salary + p.base_salary*p.bonus/100);
CREATE FUNCTION zarplata(p sale_t) RETURNING MONEY; RETURN (p.base_salary + p.comission*p.revenue/100);
Теперь можно использовать специальный синтаксис при расчете зарплаты для того, чтобы происходило позднее связывание:
SELECT zarplata(e) FROM employees e;
Специальные методы хранения, поиска и индексации
Informix DS/Universal Data Option позволяет вводить новые базовые типы данных одновременно с введением специальных алгоритмов хранения, доступа и индексирования, отличных от стандартных, реализованных в сервере.
Для введения нового базового типа данных с нестандартными методами доступа нужно определить набор серверных функций, реализующий для нового типа алгоритмы доступа, просмотра, выделения памяти и т.д. Эти функции должны быть написаны на языке C и скомпилированы в объектный формат. Далее, надо описать новый базовый тип данных, и указать функции, реализующие для этого типа алгоритмы извлечения и записи на диск значений данного типа:
{описание нового типа} CREATE OPAQUE TYPE picture ( INTERNALLENGTH=VARIABLE, . . . . . )
{реализация алгоритма записи на диск} CREATE FUNCTION assign(pic picture) RETURNS POINTER EXTERNAL NAME ‘/usr/bin/my_assign()’ LANGUAGE C NOT VARIANT;
Если мы хотим для нового типа ввести специальные алгоритмы индексации и поиска, то надо описать следующие функции:
my_am_scancost_index - оценка стоимости использования индекса
my_am_open_index - открыть внешний файл с индексом
my_am_bedinscan_index - начать просмотр по индексу
my_am_getnext_index - взять следующий элемент индекса
my_am_endscan_index - закончить просмотр индекса
my_am_close_index - закрыть внешний файл с индексом
Далее, надо указать, что вводится новый способ индексирования (pic_tree) и разработанные функции будут использоваться для индексирования созданного типа данных:
CREATE ACCESS_METHOD pic_tree( am_scancost_index = my_am_scancost_index, am_open_index = my_am_open_index , . . . . . )
Далее, использовать новый индекс можно в команде:
CREATE TABLE photos( photo picture, . . . . . ) CREATE INDEX pic1 ON photos(photo) USING pic_tree;
Возможность вводить новые типы данных совместно с новыми механизмами хранения, доступа и индексирования очень важна при разработке приложений, работающих с мультимедийными данными, а также со специальными данными типа отпечатки пальцев, карты и т.д.
- 4.5. Упражнения 67
- Глава 6. Устройство Informix Dynamic Server 165
- Глава 7. Эксплуатация информационных систем 177
- Глава 1 Обзор основных архитектур баз данных
- 1.1. Архитектура на основе разделяемых файлов
- 1.2. Архитектура “Хост-терминал”
- 1.3. Архитектура “Клиент-Сервер”
- 1.4. Архитектура с использованием сервера приложений (трехзвенная архитектура)
- 1.5. Упражнения
- Глава 2 Модели данных
- 2.1. Уровни восприятия данных
- 2.2. Иерархическая модель данных
- 2.3. Сетевая модель данных
- 2.4. Реляционная модель данных
- 2.5. Объектно-реляционная модель данных
- Глава 3 Реализация информационных систем на основе продуктов Informix Software
- 3.1. Обзор продуктов Informix
- 3.2. Варианты построения систем
- Internet/Intranet-конфигурация
- 3.3. Выбор оптимальной конфигурации
- Глава 4 Математические основы реляционных субд
- 4.1. Основные понятия
- 4.2. Ключи
- 4.3. Основные операции над таблицами и их интерпретация
- 4.4. Нормализация
- 4.5. Упражнения
- Глава 5 Язык sql
- 5.1. Типы данных, доступные в sql
- 5.3. Основные sql-операторы для доступа и модификации данных
- 5.4. Управление транзакциями
- 5.5. Продвинутые варианты оператора поиска
- 5.5.1. Поиск по нескольким таблицам
- 5.5.2. Устранение повторения данных в операторе select
- 5.5.3. Вычисления внутри оператора select
- 5.5.4. Логические выражения в условии sql-операторов
- 5.5.5. Слияние двух выборок
- 5.5.6. Сортировка выборки
- 5.5.7. Вставка в таблицу нескольких строк одновременно
- 5.6. Использование sql в языках программирования
- 5.7. Программирование сервера базы данных
- 5.7.1. Динамический sql
- 5.7.3. Хранимые процедуры
- 5.7.4. Триггеры
- 5.8. Ограничители (задание целостности на уровне схемы)
- 5.9. Разграничение в sql прав пользователей
- 5.9.1. Права доступа
- 5.9.2. Права на уровне базы данных
- 5.9.3. Права на таблицы
- 5.9.4. Права на хранимые процедуры
- 5.9.5. Кто и как следит за соблюдением прав
- 5.9.6. Механизм ролей
- 5.9.7. Псевдотаблицы (view)
- 5.9.7. Синонимы
- 5.10. Управление одновременным доступом к данным
- 5.10.1. Что бывает, когда несколько человек одновременно пытаются обновить одни и теже данные
- 5.10.2. Открытие базы данных только для себя
- 5.10.3. Блокирование таблицы
- 5.10.4. Механизм блокирования записей и уровни изоляции
- 5.10.5. Управление ожиданием снятия блокировок
- 5.10.6. Тупиковые ситуации
- 5.11. Повышение скорости обработки запросов.
- 5.11.1. Индексы
- 5.11.2. Буферизация журнала транзакций
- 5.11.3. Блокировка на уровне записей и страниц
- 5.11.4. Эффективное построение запросов
- 5.11.5. Сортировка и поиск по коротким полям. Классификаторы
- 5.12. Объектное расширение sql в Informix ds/Universal Data Option
- 5.12.1. Зачем нужна поддержка объектов в серверах бд?
- 5.12.3. Внедрение объектно-ориентированной технологии
- 5.12.4. Реализация объектного подхода в Informix
- Informix ds/Universal Data Option - объектно-реляционная субд
- 5.12.5. Итак…
- Глава 6. Устройство Informix Dynamic Server
- 6.1. Внутренняя архитектура dsa
- 6.2. Механизм хранения данных
- 6.3. Инсталляция продукта
- 6.4. Запуск и останов сервера
- 6.5. Работа с русским языком
- Глава 7. Эксплуатация информационных систем
- Администрирование серверов баз данных
- 7.2. Обеспечение сохранности данных.
- 7.2.1. Технологии постоянного дублирования
- 7.2.2. Архивация
- 7.2.3. Так как же обеспечить сохранность данных?
- 7.3. Архивирование и восстановление данных
- 7.3.1. Что нужно архивировать
- 7.3.2. Утилиты архивации и восстановления
- 7.3.3. Создание архивов утилитой ontape
- 7.3.4. Восстановление из архивов утилитой ontape
- 7.3.5. Как узнать “когда”?
- 7.3.6. Практические советы
- 7.4. Средства контроля за доступом
- 7.4.1 Как работает аудитинг?
- 7.4.2. Конфигурирование списков протоколируемых событий
- 7.4.3. Задание файлов, запуск и остановка механизма аудитинга
- Анализ протокола
- 7.4.5. Практические советы или Что делать, если вы хотите…
- 7.5. Реагирование на чрезвычайные ситуации
- 7.6. Мониторинг текущего состояния сервера базы данных
- 7.6.1. Кто работает с сервером базы данных
- 7.6.2. Сколько памяти использует сервер бд
- 7.6.3. Сколько свободного места имеется у сервера бд
- 7.7. Достижение требуемой производительности
- 7.7.1. Как узнать, что ждет некоторый запрос
- 7.7.2. Как выяснять причины падения производительности
- 2. Общие принципы предлагаемой технологии
- 3. Как портировать приложение