- •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.7. Программирование сервера базы данных
Данный параграф глава посвящена программированию сервера базы данных, то есть созданию конструкций, хоторые хранятся и исполняются непосредственно на SQL-сервере. В параграфе, в частности, рассказывается о хранимых процедурах, триггерах, описании целостности базы данных и т.д.
Когда мы говорили о схеме базы данных, то определяли ее как "набор таблиц и логические связи между ними". Но в схему могут быть включены и управляющие конструкции, в частности, процедуры. Зачем это нужно, какие преимущества дает такой подход, а также описание конкретных механизмов - всему этому и посвящен данный праграф.
5.7.1. Динамический sql
Иногда на этапе написания программы вы еще не знаете, какой именно запрос должен быть отработан сервером. Простейший пример - это порядок сортировки. В вашем приложении, предназначенном для отдела кадров, должна быть возможность отсортировать отчет по фамилии, доходу, стажу работы или числу прогулов. Причем должны быть предусмотрены все возможные
комбинации этих сортировок - по доходу и числу прогулов, по фамилии и стажу в обратном порядке и т.д. Простейший подсчет показывает - вариантов раздела ORDER BY оператора SELECT будет 81 (всего 4 поля, каждое поле допускает три разных способа использования при сотрировке - сортировать в порядке возрастания, убывания, вообще не сортировать - три в четвертой степени и есть 81). Согласитесь, что весьма утомительно указывать все 81 варианта оператора SELECT внутри программы.
В системах разработки приложений (ESQL/C, NewEra, 4GL и т.д.) имеется возможность формировать и исполнять SQL-запроса в процессе работы прикладной программы, в динамике ее исполнения. Отсюда и название - "динамический SQL" (впрочем, автор не считает это название очень удачным). Фактически, это тот же самый язык - SQL, но SQL-оператор не подвергаетсясинтаксическому разбору на этапе компиляции прикладной программы, а в текстовом виде передается непосредственно серверу базу данных.
Имеются следующие операторы для работы с динамическим SQL:
PREPARE <имя оператора> FROM <текстовая строка>
EXECUTE <имя оператора>
FREE <имя оператора>
Оператор PREPARE "подготавливает" SQL-оператор для исполнения. Сам SQL-оператор указывается либо явно в виде текстовой строки, либо через значение текстовой переменной. Оператор PREPARE "связывает" с SQL-оператором имя. Это имя - самое обычное имя в среде разработки. Примеры (Informix-4GL):
PREPARE sel1 FROM "select name from items where price < 1.50"
PREPARE empty_comp FROM "INSERT INTO companies(name) VALUES ('undef')"
Оператор PREPARE посылает переданный ему текст SQL-серверу. Сервер анализирует переданные ему SQL-операторы и, если нет ошибок, переводит их во внутреннее представление.
После того, как оператор подготовлен, он может быть исполнен оператором EXECUTE. Здесь-то и надо указывать имя, данное подготовленному оператору:
EXECUTE sel1 EXECUTE empty_comp
Один и тот же подготовленный оператор можно исполнять многократно. Оператор FREE освобождает все ресурсы (память), связанные с подготовленным оператором. Выполнять оператор FREE следует тогда, когда подговленный оператор заведомо больше не потребуется:
FREE sel1
Если не выполнить оператор FREE ничего страшного не произойдет, но выделенная для оператора память будет висеть мертвым грузом.
Если на момент подготовки SQL-оператора не все конкретные значения известны, то имеется возможность подставлять эти значения в момент исполнения. Для этого SQL-оператор, подготовленный с помощью PREPARE, должен быть снабжен параметрами. Параметры, значения которых будут определяться в момент исполнения, задаются символом "?":
PREPARE select2 FROM "SELECT price FROM items WHERE name = ?" PREPARE new_comp FROM "INSERT INTO companies(name, address) VALUES (?,?)"
Для задания фактических параметров в оператор EXECUTE надо добавить раздел USING:
EXECUTE new_comp USING "Кооператив 'Эх, ухнем'", "Москва, Арбат, 21" EXECUTE new_comp USING "ИЧП 'Бумеранг'", "Магадан, п/я 777"
Параметры в операторах PREPARE/EXECUTE являются позиционными. То есть при исполнении на место первого вопросительного знака подставляется первое значение в разделе USING, на место второго вопросительного знака - второе значение из раздела USING и т.д.
Подготовленный оператор может использоваться при описании курсора. Например, если в зависимости от желания пользователя нам надо выполнить сортировку товара либо по названию, либо по цене, то это на Informix-4GL реализуется следующим образом:
DEFINE string1 CHAR(60) .......... IF flag THEN { сортируем по названию } LET string1 = "SELECT name, price FROM items ORDER BY name" ELSE { сортируем по цене } LET string1 = "SELECT name, price FROM items ORDER BY price" END IF PREPARE select_st FROM string1 DECLARE my_cursor CURSOR FOR select_st ..........
Очевидно, можно еще сократить приведенный выше фрагмент, если использовать оператор конкатенации строк.
Помимо возможности формировать запросы не на этапе написания программы, а на этапе ее иполнения, операторы PREPARE/EXECUTE/FREE могут быть полезны еще, как минимум, в двух случаях: для повышения эффективности программы и для исполнения SQL-операторов, которые понятны серверу, но которых нет в системе разработки.
Для того, чтобы понять за счет чего подготовленные операторы могут повысить эффективность, надо разобраться как отрабатываются SQL-запросы. Когда в работе приложения управление передается на SQL-оператор, то происходит следующее. Этот SQL-оператор посылает серверу запрос на исполнение
(напомним, что все серьезные реляционные СУБД выполнены по схеме клиент-сервер). SQL-сервер исполняет запрос в четыре этапа: (1) анализирует пришедший запрос, (2) выбирает оптимальный способ его исполнения, (3) исполняет и (4) отсылает результаты приложению. Если выполнять несколько одинаковых запросов, то для каждого запроса будeт делаться все четыре этапа. Если же мы подготавливаем запрос с помощью оператора PREPARE, а затем несколько раз исполняем его оператором EXECUTE, то анализ запроса и поиск оптимального способа исполнения будет делаться только один раз - в момент выполнения оператора PREPARE. А на каждое исполнение запроса оператором EXECUTE требуется только два последних этапа - непосредственное исполнение и отсылка результатов.
Другое полезное свойство подготавливаемых операторов - это расширение возможностей среды разработки. Подготавливаемый оператор для приложения существует только как текстовая строка. Его исполнение и синтаксический разбор возложен на SQL-сервер. Поэтому с помощью операторов PREPARE/EXECUTE можно выполнить SQL-запрос, не предусмотренный в синтаксисе среды разоаботки.
Например, Вы имеете среду разработки Informix-4GL старой версии (предположим, 4-й). Она вас вполне устраивает. Но в качестве SQL-сервера используется 7-я версия Informix DS Dynamic Scalable Architecture. Этот сервер "понимает" уже значительно более широкий набор SQL-операторов по сравнению с 4-й версией Informix-4GL. В частности, оператор создания триггеров CREATE TRIGGER (о том, что это такое, будет сказано ниже) может быть исполнен сервером, но отсутствует в продукте Informix-4GL версии 4.10. Используя операторы PREPARE/EXECUTE триггер можно создать:
PREPARE cr_trig FROM "CREATE TRIGGER trig1 ..." EXECUTE cr_trig FREE cr_trig
Подготовленные с помощью оператора PREPARE SQL-запросы доступны (видимы) только в данном приложении, а именно между операторами DATABASE ... CLOSE DATABASE. То есть, если вы завершили работу (а точнее, закрыли базу данных оператором CLOSE DATABASE), то подготовленные запросы пропадают. Или, если вы подготовили SQL-запрос, то другой пользователь за другим компьютером не может выполнить подготовленный вами запрос (этот другой пользователь, конечно, может выполнить ту же самую последовательность PREPARE/EXECUTE/FREE, но это будет уже другой SQL-запрос). Однако, существует возможность подготовить для исполнения SQL-запросы так, что эти запросы будут доступны многим пользователям. Но для этого используется уже другой механизм - хранимые процедуры.