- •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. Как портировать приложение
5.12.4. Реализация объектного подхода в Informix
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;
Возможность вводить новые типы данных совместно с новыми механизмами хранения, доступа и индексирования очень важна при разработке приложений, работающих с мультимедийными данными, а также со специальными данными типа отпечатки пальцев, карты и т.д.
