СТАТЬЯ
23.11.00

(с) Дмитрий Безруков
Заместитель директора
отделения корпоративных систем

Корпорация Oracle летом 1997 года выпустила на рынок СУБД нового поколения - Oracle8 Universal Data Server. Данная СУБД выпускается в двух редакциях: полнофункциональная версия, Enterprise Edition, и относительная дешевая для рабочих групп – Workgroup Edition. В данном обзоре рассматриваются новые возможности Oracle8 Enterprise Edition. Workgroup Edition (или просто, Oracle8 Server) более дешев и обладает меньшими дополнительными возможностями. Информация о наличии или отсутствии данной возможности приводится в тексте после описания каждой возможности и резюмируется в конце.

Основное место в данной статье занимает описание общих концепций версии 8.0 (последняя версия – 8.0.5). Осенью 1998 года корпорация Oracle объявила о выходе новой версии 8.1 или 8i, как ее назвали из-за ориентации на работу в среде Internet. Большая часть статьи относится к версии 8.0. Однако Oracle8 кардинально отличается от своего предшественника, СУБД Oracle7, множеством революционных нововведений в различных направлениях компьютерной обработки больших объемов информации. Список этих направлений, приведенный ниже, также является планом данного обзора:

Распределенные вычисления

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

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

NCA обеспечивает взаимодействие картриджей, образующих распределенные прикладные системы. Картриджи при этом могут работать где угодно в сети и их пользователи могут не знать об их местонахождении. Oracle8 Universal Data Server – основная компонента NCA.

Внешние процедуры, вызываемые из PL/SQL на стороне сервера, пока можно создавать на С++, причем эти процедуры могут прямо обращаться к данным в базе и вызывать PL/SQL процедуры сервера. Картриджи, написанные на языка Java, могут общаться с данными БД через разработанный корпорацией Oracle JDBC драйвер. В ближайшее время планируется поддержка Java ядром СУБД Oracle8 (проект “Аврора”), то есть Java будет альтернативой языку PL/SQL. Будет реализована также серьезная поддержка стандарта CORBA, позволяющего интеграцию новых объектно-ориентированных разработок и существующих систем. Oracle прикладывает усилия по внедрению CORBA на серверной стороне в пяти областях: общий объектный сервис (Common Object Services), поддержка протокола IIOP, поддержка Java в базе данных наряду с PL/SQL, ORB в базе данных и поддержка Enterprise JavaBeans.

Поддержка очень больших баз данных

Коды Oracle8 были серьезно переработаны с целью улучшения поддержки очень больших баз данных (VLDB). Получен значительный выигрыш в производительности, надежности, масштабируемости. Также улучшена сетевая интеграция. Рассмотрим основные направления, по которым фирма Oracle совершенствовала СУБД Oracle8.

Разбиения таблиц и индексов (data partitioning)

Таблица или индекс могут быть разбиты на кусочки или области (partitions), каждая из которых хранится в отдельной области внешней памяти, например, в файле. Один или несколько столбцов могут быть ключом разбиения (partitioned key), значением которого определяется область, в которой размещается данная запись при insert. Например, ключом может быть диапазон месяцев или лет. Таким образом, большая таблица может размещаться в нескольких областях, возможно на разных дисках, каждая из которых управляется автономно. Если во фразе where оператора select присутствует предикат, ссылающийся на данные из одной области, то все другие области при выполнении запроса не просматриваются, и их совсем не обязательно размещать на дисках. Индексы могут быть как глобальными, строится один индекс на все области таблицы, так и локальными, то есть для каждой области свой индекс.

Администрировать области довольно просто. Есть средства для разбиения (splitting) и слияния (merger) областей. Возможен выборочный экспорт и импорт областей данных, а также выборочное резервное копирование и восстановление областей. Все административные операции над областями, а также операции по работе с данными (select, insert, delete, update) могут распараллеливаться для повышения производительности.

Необходимое программное обеспечение присутствует в стандартном дистрибутиве, но для того, чтобы использовать разбиение, Вы должны приобрести лицензию на Partitioning Option за дополнительную плату. Partitioning Option не может быть установлен на Oracle8 Universal Data Server Workgroup Edition. Также Workgroup Edition не допускает распараллеливания обработки.

Поддержка оперативных транзакций (OLTP)

Oracle8 может поддерживать значительно больше одновременно работающих пользователей, чем его предшественник, Oracle7. Разработчикам прикладных систем предоставляются новые возможности кэширования в оперативной памяти сервера блоков, содержащих данные различных объектов. Теперь предоставляется три кэша, а не один как было ранее и при создании, модификации объекта, а также в запросе можно указать, в какой их кэшей считывать блоки данного объекта. Эти кэши могут использоваться разработчиками для управление хешированием блоков таблиц и индексов в различных типах запросов. Oracle8 Workgroup Edition обладает этой возможностью.

Управление соединениями на сервере или connection pooling

Эта новая возможность в сетевом программном обеспечении Oracle8, пришедшем на смену SQL*Net и названном Net8. Позволяет осуществлять временный разрыв линии связи со стороны сервера для простаивающих пользователей с последующим прозрачным ее восстановлением. Используется только в многопотоковом сервере (MTS) при взаимодействии по схеме “клиент-сервер”. Oracle8 Workgroup Edition обладает этой возможностью.

Управление соединениями на клиенте или connection multiplexing

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

Управление соединениями между серверами или shared database links

Обеспечивает мультиплексирование линий связи при коммуникациях типа “сервер-сервер”.

Улучшения OLTP

Также было сделано несколько небольших, но очень существенных доработок для повышения эффективности обработки оперативных транзакций (OLTP):
Если оператор select выполняется непосредственно после занесения данных оператором insert или обновления оператором update, то экономится одна сетевая передача (round trip).
При обработке фазы execute оператора select в OCI Oracle8 передается также часть выбранных данных (pre-fetching).
Улучшен сетевой трафик в ODBC.
Параметры из переменной окружения NLS_LANG на клиенте во время подсоединения к Oracle теперь передаются без помощи операторов alter session, уменьшая сетевой трафик и время подсоединения.
Уменьшены потребности сеансов пользователей в оперативной памяти (PGA и UGA) на 30-60%.
Существенно улучшены алгоритмы диспетчеризации и взаимодействия между диспетчерами и серверами в многопотоковом сервере (MTS).
Существенно улучшены алгоритмы работы с SQL Areas и Dictionary Cache.
Существенно улучшен алгоритм преобразования кодовых страниц при передаче символьных данных между клиентом и сервером.
Вызов функций, написанных на PL/SQL, из операторов SQL стал быстрее на 40%.
Динамический SQL в Oracle8 выполняется также быстро, как и обычный статический.
Значительно сокращено время при вызове SQL из PL/SQL.
Индексные таблицы позволяют хранение данных непосредственно в индексах, не используя сегменты данных.
Значительно улучшены алгоритмы с работы с таблицами в памяти (in-memory tables) на PL/SQL.
Ряд других мелких доработок

Улучшения в интерфейсе XA для мониторов транзакций (TP monitors)

Добавлена динамическая регистрация.
Поддержка слабосвязанных ветвей транзакций (loosely-coupled transaction branches).
Кэширование сеансов не используется.
Библиотеки XA поддерживаются в OPS для всех платформ.
В рамках одного соединения XA поддерживаются как глобальные, так и локальные транзакции.

Поддержка электронных хранилищ данных (data warehouses) в Oracle8

Было сделано несколько существенных улучшений работы оптимизатора запросов для построения более оптимальных путей доступа к данным:

При оптимизации запросов по схеме “звезда” теперь возможен эффективный просмотр нескольких больших факт-таблиц, а не одной, как это было в Oracle7.
Реализована более эффективная работа с таблицами размерностей. Вместо декартова произведения, поменявшегося в Oraclе7 теперь возможно использование растровых (bit-mapped) индексов.
Улучшен алгоритм обработки растровых индексов.
Возможно распараллеливание при просмотре не только таблиц, но и индексов.
Также был добавлен целый ряд новых возможностей для более быстрой загрузки и модификации данных в электронных хранилищах:
Возможно распараллеливание всех операторов DML (insert, delete, update) для таблиц с разбиениями (partitioned tables), и только insert для обычных (non-partitioned) таблиц.
Возможна прямая запись (direct writes) в файлы базы данных без использования промежуточной записи в кэш (данные вставляются после high water mark в таблице); работает очень быстро. В Oracle7 такая возможность реализована только в SQL*Loader. Однако, существуют серьезные ограничения на использование распараллеливания и прямой записи, так как большинство ограничений целостности должно быть отключено и блокировки распространяются на уровень таблиц. Эти возможности не предназначены для использования в OLTP, а только при загрузке и разовых модификациях данных в электронных хранилищах.

Обмен сообщениями

Обмен сообщениями в Oracle7.

Обмен сообщениями в Oracle8. Механизм очередей (Advanced Queuing (A/Q).

Наряду с пакетами, описанными выше, в Oracle8 разработано новое средство для обмена сообщениями - A/Q, реализованное в виде двух пакетов: DBMS_AQ и DBMS_AQ_ADM. Это средство позволяет:

Oracle8 Workgroup Edition не обеспечивает механизм A/Q.

Поддержка слабосвязанных вычислительных сред

Корпорация Oracle серьезно переработала Oracle Parallel Server (OPS)– продукт для работы с данными в слабосвязанных кластерных архитектурах. Улучшения направлены в основном на увеличение производительности в больших вычислительных комплексах. Основные из них перечислены ниже:

Oracle8 Workgroup Edition не обеспечивает OPS option.

Новый инструментарий для резервного копирования/восстановления (backup/recovery)

Корпорация Oracle разработала совершенно новый инструментарий для резервного копирования/восстановления. В дополнение к средствам резервного копирования/восстановления Oracle7, осуществляемое средствами базовой ОС, инструментарий Oracle8 входит в ядро системы. Как копирование, так восстановление осуществляется фоновыми процессами СУБД.

Для управления процессами копирования/восстановления и хранения информации, собираемой при копировании/восстановлении, была разработана новая утилита, названная Recovery Manager. Учетная информация о том, когда были сделаны резервные копии, копии какой части базы данных они содержат и т.д. могут храниться в репозитарии, располагающемся в таблицах специально отведенной для этого СУБД, или в управляющем файле (control file), копируемой СУБД. Эта информация собирается во время копирования и используется при восстановлении, освобождая пользователя от необходимости вести вручную учет резервных копий. Можно также получить удобные отчеты о содержании репозитария или управляющего файла. В процессе копирования может осуществляться упаковка данных для уменьшения объема хранимых копий.

Теперь поддерживается инкрементальное резервное копирование/восстановление (incremental backup), позволяющее записывать в текущую резервную копию только блоки, модифицированные с момента предыдущего копирования.

Поддерживается резервное копирование на магнитную ленту. Для этого в ядро СУБД должны быть включены библиотеки модуля управления внешними носителями, поставляемые третьими фирмами. Oracle отдает предпочтение программе управления носителями Legato.

Recovery Manager предоставляет пользователю специальный язык для программирования процессов копирования/восстановления. Для облегчения работы с Recovery Manager, была создана специальная утилита Backup Manager, входящая в состав Oracle Enterprise Manager (см. ниже) и предоставляющая пользователю удобный графический интерфейс для резервного копирования/восстановления.

Recovery Manager также поддерживает возможность восстановления отдельного табличного пространства (tablespace) базы данных на момент в прошлом (point-in-time recovery или, сокращенно, PITR).

Симметричное тиражирование (Symmetric Replication)

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

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

Тексты всех триггеров для тиражирования, ранее написанных на PL/SQL, были переписаны на языке С (internalized triggers), что также увеличило производительность и снизило накладные расходы.

Теперь используется быстрый механизм для передачи сообщений - A/Q (см. выше). Утверждается, что механизм симметричное тиражирование в Oracle8 можно использовать в системах оперативного дублирования (standby systems).

Сложный снимок (snapshot), базирующийся на подзапросе (complex subquery snapshot), может теперь включать фразу быстрого обновления (refresh fast), что позволяет создавать более гибкие прикладные системы.

В Oracle8 упростилось администрирование тиражирования. Переработанная утилита Replication Manager теперь предоставляет пользователю значительно более удобный графический интерфейс.

Oracle8 Enterprise Edition содержит средства для обеспечения симметричного тиражирования в базовом дистрибутиве, приобретать отдельную лицензию на их использование не нужно. Workgroup Edition не включает средства для симметричного тиражирования, хотя предоставляет возможности для использования снимков для просмотра (read only snapshots).

Безопасность работы с данными.
Аутентификация и авторизация

Аутентификация средствами СУБД

Oracle8 предлагает ряд поддерживаемых СУБД средств для администрирования пользователей. Такие средства обычно характерны для операционных систем. К ним относятся:

Сервер безопасности (Oracle Security Server)

Как и Oracle7, Oracle8 предоставляет возможность аутентификации через операционную систему. В этом случае пользователь для входа в Oracle пользуется именем и паролем операционной системы. Для подсоединения к Oracle нужно просто задать “connect /”.

Новой в Oracle8 является возможность аутентификации пользователя через сертификаты x.509, содержащие электронные подписи. Сертификат используется вместо пароля, причем обеспечивается взаимная аутентификация между клиентами, серверами и Web-серверами.

Обеспечивается централизованное хранение и администрирование пользователей. Поддерживаются глобальные пользователи и роли и группы глобальных ролей. Пользователь, получив свой сертификат, может входить на каждый сервер под своим именем без пароля (single sign-on), в том числе и по database link (сервер-сервер). Синтаксис оператора подсоединения такой же, как и в аутентификации через операционную систему.

Oracle Security Server, входящий в состав Oracle Enterprise Manager, хранит информацию обо всех глобальных пользователях централизованно, давая лучшую безопасность и удобное администрирование распределенных БД. Такой подход имеет преимущества в том случае, когда пользователи работают с данными, распределенными по многим серверам в сети. Глобальная аутентификация пользователей и авторизация через глобальные роли значительно облегчает жизнь администраторам. Пользователи также не должны периодически менять свои пароли на всех серверах, как это обычно делается с целью повышения уровня безопасности.

Улучшенное сетевое обеспечение (Advanced Networking Option (ANO)

К сетевому обеспечению СУБД Oracle7, называемому SQL*Net, можно было приобрести дополнительную лицензию на Advanced Networking Option (ANO). Лицензию на ANO можно также приобрести и в дополнение к сетевому ПО Oracle8, называемому Net8. ANO обеспечивает некоторые интересные возможности и должно быть упомянуто в данном обзоре.

ANO поддерживает дополнительные возможности по аутентификации, а именно:

Oracle8 Universal Data Server Workgroup Edition не поддерживает Advanced Networking Option, а следовательно, не может поддерживать и шифрование информации при передаче по сети.

Низкоуровневый интерфейс в среде клиент-сервер

Oracle8 предлагает новый клиентский интерфейс для работы прикладной программы, на процедурном языке третьего поколения (пока это С++) с данными базы, кэшируемыми на стороне клиента – Oracle Call Interface and Client Side Cache. Этот объектно-ориентированный интерфейс является, пожалуй, самым серьезным улучшением в Oracle8 и кардинально отличается от OCI версии 7.

В новом OCI при чтении данных сначала осуществляется просмотр кэшированных в памяти клиента данных. Все процессы, использующие OCI, могут пользоваться кэшем, то есть кэшируемые данные являются общими для всех пользователей, работающих с OCI на данном клиентском компьютере. Вместо управляющих областей памяти старого OCI теперь используются общие области памяти – handles. Каждый внешний сервер, сеанс с Oracle на данном клиенте, предложение SQL и транзакция имеют свои handles.

Все буферизуется в кэше на стороне клиента и все разделяется между сеансами, например, один сеанс может начать транзакцию, а другой – закончить. Такой подход позволяет легко написать собственный TP монитор или 3-tired приложение.

Кроме того, новый OCI включает средства для написания объектно-реляционных программных модулей. Предусмотрена возможность неявной записи в базу данных из кэша на клиенте. То есть, программист не должен явно выдавать операторы DML (insert, delete и update), что довольно утомительно при написании объектных программ. Здесь уместно упомянуть, что объекто-реляционный подход недоступен в Oracle8 Workgroup Edition.

Оъектно-реляционный подход к разработке прикладных систем

Oracle 8 поддерживает абстрактные типы данных (АТД), то есть можно конструировать новые типы данных из базовых (строковых, числовых, и т.д.). Эти новые типы могут использоваться (с некоторыми ограничениями) там, где ранее в Oracle7 можно было использовать базовые типы. Кроме того, АТД могут содержать методы. Методы описываются как процедуры и функции на PL/SQL, называемые составляющими (member procedures and functions), которые работают для каждого объекта данного типа.

В Oracle8 пока поддерживается три типа АДТ:

VARRAY и TABLE являются коллекциями (collections) объектов, то есть может храниться несколько экземпляров объектов данного типа.

Для манипулирования хранимыми в СУБД объектами корпорация Oracle реализовала язык SQL3 (стандарт SQL3 пока не принят, но проект (draft) опубликован). Примеры объектно-реляционного программирования приведены в приложении 1. Не следует забывать, что объектно-реляционный подход сильно отличается от объектно-ориентированного.

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

Пока инструментарий для разработки объектно-реляционных прикладных систем включает PL/SQL со стороны СУБД, OCI для С++ на клиенте и Oracle Web Application Server на промежуточном уровне. Java с возможностью доступа в данным базы через OJBC драйвер также косвенно можно рассматривать как объектно-реляционный инструмент. С внедрением CORBA этот инструментарий существенно пополнится.

Корпорация Oracle планирует выпуск средства для проектирования объектно-реляционных систем, называемое Oracle Object Database Designer или ODD. В качестве языка для проектирования ODD, входящий в состав Oracle Designer/2000, поддерживает Unified Modeling Language (UML). ODD может генерировать типы объектов и фрагменты кодов на PL/SQL и C++.

Для использования объектно-реляционного подхода при разработке систем необходимо дополнительно приобрести лицензию на Object Option, которая доступна только в Oracle Universal Data Server Enterprise Edition и недоступна в Workgroup Edition.

Средства администрирования в Oracle8

Наряду с уже упомянутыми Oracle Security Server, Recovery Manager и Replication Manager, усовершенствованы основные инструменты администратора, такие как Oracle Enterprise Manager и Oracle Intelligent Agent. Хотя они мало отличаются от своих предшественников функционально, интерфейсы сильно изменились в лучшую сторону.

Разные улучшения в Oracle8

В данном обзоре была предпринята попытка классификации новых возможностей Oarcle8. Однако есть ряд новшеств, которые классифицировать затруднительно. Они перечисляются в этом разделе.

Большие объекты (Large Objects или LOB)

Для хранения и обработки данных большого объема, таких как картинки, тексты, двоичная информация в Oracle7 были предусмотрены поля типа long и long raw. Поиск по этим полям невозможен при помощи оператора select, хотя и легко реализуем с помощью функций PL/SQL, вызываемых из SQL. Такие поля обладают рядом недостатков, а именно:

Oracle8 предлагает новые типы данных CLOB (Character Large OBject) и BLOB (Binary Large OBject), свободные от этих недостатков. Как и long, эти типы данных не предназначены для поиска на языке SQL, но их можно хранить как внешним образом в файлах операционной системы, так и отдельном табличном пространстве СУБД. Их можно как читать, так и писать (в том числе и обновлять) по частям. В отличие от LONG, эти поля нельзя выбирать напрямую оператором SQL, а только через PL/SQL.

Триггеры instead of insert/delete/update для views

Oracle8 допускает создание триггеров для представлений пользователей (views). Эти триггеры срабатывают при применении операторов DML к представлению и особенно полезны, когда представление пользователя объединяет несколько таблиц СУБД. При помощи этих триггеров разработчик может задавать собственную логику обновления представлений пользователей. Эти триггеры также полезны при работе с объектными представлениями (см. выше).

Отложенная проверка ограничений целостности (deferrable constraints)

В Oracle8 проверка ограничений целостности может выполняться не сразу после выполнения операторов insert, delete или update, а откладывается до фиксации транзакции оператором commit.

Уникальные (unique) и первичные (primary) ключи могут поддерживаться через неуникальные (non-unique) индексы.

Эта возможность освобождает администратора от необходимости уничтожения индексов при выключении (disabling) ограничения (primary key или unique key).

В Oracle8 допускается помещать курсор в список оператора select (select list) вместо столбца.

Это позволяет прямую выборку из дочерней таблицы без операции соединения.

Новые возможности Oracle8i

Здесь описываются новые возможности Oracle 8 Enterprise Edition version 8.1, называемой также Oracle8i, которая поступит в продажу в 1999 году. Описание новых возможностей взято из материалов корпорации Oracle и из различных статей и может отличаться от возможностей первой официальной версии Oracle8i. Естественно, не все возможности будут реализованы в первом релизе.

Структуры базы данных и языки программирования в Oracle8i

Объявлено о реализации Java-машины в RDBMS. Предполагается, что на Java будет возможна такая же разработка, как и на PL/SQL. Возможна разработка хранимых процедур и триггеров. Java и PL/SQL смогут работать совместно.

В SQL добавлены средства для удаления столбца из таблицы.

Сделан ряд существенных улучшений в PL/SQL, которые включают новый оператор для вызова динамического SQL (оператор EXECUTE IMMEDIATE … USING), новые возможности по вызову и выполнению процедур. Параметры в процедурах и функциях теперь можно быстро передавать по ссылке (NOCOPY), а не по значению. Добавлены средства для выявления узких мест в программе наиболее сильно влияющих на производительность (profiler API). Сокращено время переключения контекста между SQL и PL/SQL. Добавлен отладчик кода PL/SQL (DBMS_DEBUG API и DBMS_TRACE API). Практически сняты ограничения на размеры пакетов. Процедуры теперь можно вызывать с правами пользователя не только владельца, но и самой процедуры. Добавлена возможность выполнения автономных транзакций вне контекста текущей транзакции. Во фразе FROM оператора SQL SELECT с помощью ключевого слова TABLE() можно указывать имена таблиц в оперативной памяти PL/SQL и коллекций (VARRAYs, NESTED TABLES). Возможно задание пользователем своих собственных операций. Методы теперь могут быть статическими (STATIC). Типы объектов и коллекции теперь могут быть переданы как параметры в процедуры. Существенно увеличена производительность за счет оптимизации кода ядра, например, существенно улучшилась производительность при вызове стандартных функций (TO_CHAR, SUBSTR и т.д.). Значительно увеличена производительность при вызове удаленных процедур.

Значительно усовершенствованы разбиения (partitions). Разбиения могут быть применены к объектным таблицам, таблицам с индексной организацией (index organized tables), таблицам, содержащим большие объекты (LOBs) и ссылки REFs. Кроме того, в дополнение к единственному способу разбиений в Oracle8 v8.0 по диапазонам, добавились новые типы разбиений, составное (composite) и хэшированное (hash) для повышения равномерности распределения строк в разбиениях и большего распараллеливания и ускорения выборок. Теперь разбиения можно сливать командой alter table merge partition. Возможна модификация ключей разбиения с перемещениями строк данных. Названия разбиений теперь можно указывать не только в операторах select, но также и в операторах DML. Существенно улучшен алгоритм просмотра разбиений и теперь при наличии в операторе IN списка значений просматриваются только нужные куски.

В Oracle8i допустимо создание индексов на таблицы с индексной организацией (index organized tables),

Данные типа LOB могут быть временными (temporary), то есть храниться во временном табличном пространстве на протяжении жизни сеанса, не участвовать в обработке транзакций. Используются, например, для преобразования multimedia информации из одного формата в другой. Для данных типа LOB добавилась также поддержка для преобразования из типа LONG.

В Oracle8i, наконец, появились временные таблицы (temporary tables). Временные таблицы предназначены для хранения данных на протяжении работы сеанса или транзакции. При модификации временных таблиц журнальная информация (redo log) не генерируется. Допустимо создание индексов для ускорения работы с временными таблицами. Новый оператор create global temporary table и фразы on commit delete rows и on commit preserve rows добавлены для временных таблиц.

В Oracle8i индексы можно создавать не только по значениям столбцов, но и по возвращаемым значениям функции. Это называется индексами, базирующимися на функциях (function-based indexes). Такие индексы полезны при задании столбца в качестве аргумента функции во фразе where а также позволяют использовать индекс для выполнения лингвистической сортировке по-русски. Например, индекс, созданный фразой create index Ename_idx on emp (upper(ename)); позволяет использовать индекс в запросе select *from EMP where upper(Ename)='SMITH'; Значения столбцов таблицы в индексе теперь могут располагаться в убывающем (descending) порядке, а не только в возрастающем, что позволяет использовать индекс при упорядочивании по убыванию.

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

Введена концепция управляемых локально табличных пространств (locally managed tablespaces). Предполагается, что табличное пространство этого типа состоит из экстентов одинакового размера, причем при добавлении и удалении экстента их табличного пространства операций над словарной системой Oracle не производится, то есть информация о свободных и занятых экстентах располагается внутри табличного пространства.

Для экономии времени при вычислении промежуточных результатов обработки запроса Oracle8i позволяет хранение и использования промежуточных результатов выполнения запроса в материализованных представлениях (materialized views). Материализованное представление – это таблица, создаваемая пользователем и предназначенная для хранения агрегированных промежуточных данных или результатов операций соединения (join)при работе с хранилищами данных (data warehouses) и в системах OLAP. На базе таких представлений поддерживаются таблицы-суммы (summary tables), а также осуществляется другая денормализация данных. Оптимизатор запросов в Oracle8i обладает возможностью перекомпоновки запросов (query rewrite), то есть умеет использовать данные, хранящиеся в материализованных представлениях вместо операций агрегирования и/или соединения, существенно ускоряя время выполнения запроса. Материализованные представления обновляются по запросу пользователя, либо автоматически через заданные интервалы. Введены новые команды CUBE и ROLLUP. Допустимы запросы типа Top-N для выявления выборки минимального и максимального значений из набора данных.

Существенные улучшения были сделаны в оптимизаторе запросов (optimizer). Помимо поддержки материализованных представлений, разбиений и индексов, базирующихся на функциях, добавлен ряд возможностей. При распределенной обработке соединение двух таблиц, расположенных на удаленном узле, теперь выполняется на этом же узле. Если несколько таблиц с разбиениями секционированы по одинаковым столбцам, то соединения этих таблиц производятся по схеме “разбиение-разбиение” (partition-wise join). В Oracle8i допустимо хранение в базе данных планов выполнения (execution plans) для операторов SQL. Если план хранится в базе данных, то оптимизатор всегда его использует, а не строит каждый раз новый план выполнения. Таким образом, существует возможность создания стабильной навигации для часто выполняемых операторов SQL.

Oracle8i предлагает возможность оперативной реорганизации индексов и таблиц с индексной организацией (index organized tables), которые могут создаваться и/или перестаиваться в то время как пользователи модифицирую в них данные. Также добавилась команда alter index coalesce для устранения фрагментации в существующем индексе.

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

В объектно-реляцонном подходе в Oracle8i могут быть заданы ссылочные ограничения целостности для столбцов типа REF.

Сбор статистики командой ANALIZE в Oracle8i может распараллеливаться.

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

Серверная компонента в Oracle8i

СУБД Oracle была серьезно модифицирована с целью увеличения производительности. Рассмотрим эти модификации:

Новый программный продукт, называемый LogMiner позволяет пользователю анализировать журналы (в том числе и архивные) изменений базе в данных. Продукт позволяет восстановление по журнальным файлам (redo logs и archived redo logs) DML операторов (insert, update, delete) из транзакции, в прошлом изменившей данные базы. Кроме того, LogMiner позволяет генерацию операторов DML, аннулирующих результаты какой-либо проведенной ранее транзакции. LogMiner может быть использован для исправления ошибки пользователя, занесшего неверные данные в базу - например, для восстановления данных. Первоя версия LogMiner не сможет работать с операторами update, а также с типами данных LOB и LONG.

Два процесса, производящие основной ввод/вывод с/на диски, DBWR и LGWR теперь могут использовать ввод/вывод списками (list I/O или LIO). Некоторые операционные системы, например Solaris 2.6, предоставляют эту возможность. Суть ее состоит в том, что программа, производящая ввод/вывод, может послать в ядро операционной системы список запросов на ввод/вывод различных областей памяти. Теперь возможно чтение нескольких несмежных блоков, как из индекса, так и из области данных за одну операцию ввода/вывода.

Работа с индексами при распараллеливании DML осуществляется при помощи специально выделенных для этого процессов.

Был сделан ряд существенных улучшений в алгоритмах восстановления данных после сбоя. Теперь администратор данных может регулировать время, необходимое для восстановления данных после сбоя системы. Увеличена производительность СУБД за счет ускорения выполнения контрольной точки. Введена инкрементальная контрольная точка, за счет чего может регулироваться время восстановления после сбоя. Значительно уменьшена вероятность конкуренции между несколькими работающими процессами DBWR Возможно задание нескольких одновременно работающих процессов ARCH. Возможно задание до 5 каталогов для архивирования. При сортировке теперь нельзя отключить прямую запись на диск.

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

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

Существенно улучшены сортировки. До Oracle8i увеличение объема виртуальной памяти, отведенной под сортировку не влекло за собой пропорционального увеличения скорости сортировки, а иногда приводило к замедлению. В Oracle8i это изменилось и можно управлять скоростью сортировки, регулируя отводимую область памяти. Следующие параметры теперь не используются: sort_direct_writes, sort_write_buffers, sort_write_buffer_size и sort_read_fac.

Сделан ряд улучшений в области баз данных для горячего резервирования (standby databases). Теперь появление архивного журнала на диске отслеживается автоматически и накат его на базу данных горячего резервирования также может осуществляться автоматически. Также можно открыть базу данных для горячего резервирования “ только на чтение”, просмотреть, потом закрыть и продолжить накат архива без пересоздания резервной базы данных.

Появились новые средства для выявления поврежденных блоков данных на ранних стадиях. Также разработан специальный новый пакет DBMS_REPAIR для анализа и восстановления сбойных блоков.

Ряд усовершенствований было внесено в параллельную обработку запросов (parallel query option). Oracle8i может теперь обеспечить (распараллеливать) выполнение запросов, параллельная обработка которых была ранее недоступна.

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

Много-потоковый сервер (multi-threaded server или MTS) был серьезно модифицирован. Значительно упрощен интерфейс пользователя для конфигурирования MTS. Теперь работает алгоритм для балансировки нагрузки при использовании параллельного сервера: MTS сам выбирает наименее загруженный узел в кластере. Реализована поддержка нескольких динамических слоев презентации (Multiple Dynamic Presentation Support): работать можно не только через Net8, а также через IIOP, HTTP, FTP или через заданный пользователем уровень. MTS теперь поддерживает Enterprise Java Beans.

Серверная компонента ConText Cartridge серьезно модифицирована. Для хранения полнотекстовых индексов предполагается использование index organized tables.

Улучшен Recovery Manager. Переделан интерфейс с менеджером внешних носителей (Legato или другие). Вывод команд List и Report стал значительно более читабельным. Добавлены новые команды работы с каталогом и с базой данных (startup, shutdown, alter database …). Можно создавать клоны базы данных и делать резервное копирование с дублированием.

Есть также несколько существенных улучшений в Oracle Parallel Server (OPS). Теперь при необходимости блок в некоторых случаях может быть передан прямо из памяти одного узла в память другого без операции записи на диск и чтения с диска (ping). Поддерживается работа в режиме сбалансированной нагрузки, когда сеанс пользователя, подсоединяющегося к Oracle, выполняется наименее загруженным экземпляром.

Средство для администрирования баз данных, Oracle Enterprise Manager, предполагается значительно расширить и переписать на Java, что позволит сделать OEM независимым от платформы.

В Oracle8i проделана большая работа по переносу кода для репликаций непосредственно в ядро. Теперь на мастер-узле можно задавать снимок на удаленном узле (snapshot refresh group templates), которым можно секционировать как горизонтально, так и вертикально.

Значительно упрощена инсталляция Oracle8i.

Oracle8i содержит специальный программный интерфейс (API) для разработки картриджей. Добавлены специальные средства для обеспечения безопасности данных на промежуточном уровне в трехуровневой архитектуре.

Oracle8i впервые предлагает средства для диагностики системных ошибок.

Oracle8i и Internet

Oracle8i предлагает продукт, названный WebDB, для создания Web-приложений (развитие Web Application Server). Продукт предназначен для создания динамических Web-приложений и контекстно-управляемых сайтов. WebDB целиком располагается в базе данных Oracle и для работы с ним не нужно ничего, кроме браузера.

Для работы с мультимедийными данными Oracle8i предлагает пакет продуктов iMedia, предназначенный для работы в Internet, так и для работы с традиционными приложениями. IMedia включает в себя: iMedia-Image для манипуляций изображениями, iMedia-Audio для получения аудиоинформации, iMedia-Video для работы с видеоинформацией, iMedia-Locator для работы с пространственной информацией в GIS системах, например, дать координаты всех объектов определенного класса, расположенных на заданном расстоянии от какого-либо объекта, iMedia-Text для работы с полнотекстовой информацией в Web-приложениях (развитие Oracle ConText Option).

Новый продукт в Oracle8i, называемый Internet File System (iFS) предназначен для универсального доступа к различным ресурсам. Как файловая система OS, так и база данных Oracle8i представляется для пользователя Web единым способом. Причем реляционными данными можно манипулировать так же, как и обычными файлами. iFS облегчает работу с разнородными данными, представляя их универсальным образом для хранения и обмена сообщениями.

Для написания приложений на Java пользователи могут воспользоваться JDBC 2.0 или транслятором SQLJ 1.0. Для разработки можно использовать 3 модели: хранимые процедуры на Java, Enterprise Java Beans 1.0 или CORBA 2.0.

Приложение 1. Примеры объектов в Oracle8.

Концепция объектов.

Хранимый (persistent) объект может быть как строкой таблицы (в этом случае говорят об объектных таблицах). Объект также может быть значением столбца обычной таблицы. Временный (transient) объект создается в памяти и уничтожается после окончания работы (как в С++, PL/SQL ...). Временные объекты можно делать постоянными, отправляя их на хранение в базу данных. Можно также извлекать из БД постоянный объект и помещать его во временный с таким же типом.

Тип объекта (абстрактный тип данных и методы) хранится в словарной системе СУБД, а экземпляр хранимого объекта - в таблице (-цах) как значение столбца обычной или строка объектной таблиц. В дальнейшем для краткости я буду называть экземпляры объектов просто объектами.

Выборка и манипулирование хранимыми объектами в базе данных возможна только на языке SQL3. Работа с временными объектами - на PL/SQL (на стороне сервера), C++ (на стороне клиента с применением client-side cache плюс возможность вызова программ на C++ из PL/SQL) и планируется Java (на всех трех слоях).

Типы объектов всегда хранятся в словарной системе СУБД. Далее приводится пример создание типа объекта адрес с атрибутами улицы города и почтового индекса и типа объекта персоналия, включающего в качестве атрибута тип адрес. Это скалярные объекты. Для типов объектов, содержащих методы, должно быть задано тело (body), содержащее исходные коды методов.

create type address as object ( --содержит только атрибуты
   Street varchar2(40) -- улица
   , City varchar2(30) -- город
   , Zip number(8) -- почтовый индекс
   );
create type person  as object (-- атрибуты + метод Age
      First_name varchar2(15) -- имя
    , Last_name varchar2(30)  -- фамилия 
    , Addr address            -- адрес (название типа адреса)
    , Birthday date           -- дата рождения
    ,  member function Age –-спецификация метода, возвращающего возраст
                 return number – возвращаемое значение
 );
create or replace type body person is -- задание методов
 member function Age return number is -- программа для вычисления
    begin                             -- возраста по дате рождения
     return  round(months_between(sysdate, Birthday)/12);
    end;
 end;

Временные объекты

Временные объекты создаются с помощью конструкторов. Имена конструкторов совпадают с названиями типов объектов. Нельзя создавать собственные конструкторы.

declare  -- создание временных экземпляров объектов
   Dima person;  -- Переменная для экземпляра типа person
   Dimaage number; -- Переменная для кирпичика
begin
 -- Person и Address - конструкторы
 Dima := person(‘Дмитрий’,‘Безруков’, 
 address (‘Восточная 25/8’, ‘Москва’,  194535), ‘07.07.51’ );
 Dimaage := Dima.age();
 . . .|
 end;

Однотипные объекты можно сравнивать между собой. Сравнение объектов производится при помощи определяемых пользователем методов MAP (для каждого объекта возвращает число, на основе которого производится сравнение) и ORDER (аргументом этой функции является другой объект данного типа и возвращаемые значения –1 – меньше, 0 – равно и +1 – больше).

Созданный временный объект может быть занесен в столбец реляционной таблицы или в строку объектной таблицы.

Объекты в столбцах обычной таблицы

create table EMPLOYEES  ( -- таблица СЛУЖАЩИЕ
 ,     Empno number(4) primary key –- номер служащего
   , Personal person –- объект персоналии
 ,     Deptno number(4)-- номер отдела, в котором работает
 ,     Salary number(7,2) -- зарплата
 ,     Commission number(7,2) -- премия
 );
При занесении и обновлении данных в столбце Personal можно использовать 
конструкторы
в нашем случае person и address): insert into EMPLOYEES values ( 2000, person(‘Дмитрий’,‘Безруков’, address (‘Восточная 25/8’,‘Москва’,194535), ‘07.07.51’), 1000, 500);

Обращение к подъобектам можно осуществлять через квалификатор – символ точка “.”:

Update EMPLOYEES E set E.Personal.Addr.Street = ‘Тверская’
  where Personal.Addr.Street like ‘Восточная%’;
Select  E.Personal.Last_name, E.Personal.Age()from EMPLOYEES
  where E.Salary between 1000 and 5000;

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

Объекты в строках объектных таблиц

Работа с объектами в объектных таблицах также осуществляется на SQL3. Ограничения целостности для объектных таблиц не работают (кроме primary и unique keys). Можно создавать индексы, в том числе и конкатенированные на атомарные подобъекты объектных таблиц. Нельзя создавать индексы на коллекции (см. далее). Ссылки (см. далее) допустимы только на объекты, хранящиеся в объектных таблицах, а не на объекты в столбцах обычной таблицы.

Объектные таблицы можно создавать при помощи следующей конструкции:

create table PEOPLE of person 
   ( Last_name primary key –- влечет создание индекса по Last_name);

Вставка строки в таблицу осуществляется аналогично.

insert into PEOPLE values (
 person( ‘Дима’,  ‘Безруков’, 
 address( ‘Восточная 25/8’,  ‘Москва’, 194535))
 );

Выборка происходит через метку таблицы:

select P.First_name, P.Last_name, P.Age(), P.Addr
 from PEOPLE  P
 where P.Age() > 35;

Ссылки на объекты

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

Declare Reftodima ref person; -- переменная для ссылки 
 begin                         -- на объект типа Person
        select ref(P) into Reftodima from PEOPLE P 
        where P.Last_name = ‘Безруков' for update;
        update PEOPLE P set P.Addr.Street=’Тверская, 5’
        where Ref(P) = Reftodima;
  end;

Значение в ссылке можно заменить на несуществующее (dangling) при помощи оператора DEREF:

create type project as object  ( -- тип проекты
      Projno number(5)     -- Каждый проект ведет
   ,  Emp_ref ref person); -- один служащий
create table PROJECTS of project; -- создание объектной таблицы
 declare reftodima ref person;
      begin   -- Занесение одного объекта в таблицу PROJECTS
        select ref(p) into reftodima
        from PEOPLE P where P.First_name = ’Дмитрий';
        insert into PROJECTS values (1, reftodima);
        commit;
      end;

Выборка из таблиц PEOPLE и PROJECTS с существующими ссылками. Отметьте, что во фразе from указана только таблица PROJECTS.

select Projno, Deref(Emp_ref) from PROJECTS P
 where P.Emp_ref is not dangling;

Для ссылок есть предикаты: IS DANGLING и IS NOT DANGLING. Оператор Deref автоматически по ссылке извлекает требуемый объект (строку) из объектной таблицы, на которую указывает данная ссылка. Идентификатор таблицы PEOPLE содержится в ссылке - уникальном идентификаторе объекта и автоматически извлекается оттуда при обращении по ссылке. Таким образом, ссылка в поле PROJECTS.Emp_ref может указывать на строку любой объектной таблицы типа Person, а не только таблицы PEOPLE.

Коллекции – массивы (Varrays)

Рассмотрим работу с коллекциями, число элементов в которых ограничено:

create type Box as varray(3) of number;
     create table PRODUCTS ( -- создадим обычную таблицу
        Product_id number primary key – идентификатор изделия
 ,      Product_name varchar2(30) not null – наименование изделия
 ,      Dimensions box not null – длина, ширина и высота коробочки  
 );
Теперь вставим строчку в таблицу PRODUCTS:
 insert into PRODUCTS values (42, ’Торт ”Пролет"', box(12,30,30));
 commit;

И выведем результаты с помощью анонимного блока PL/SQLL

     declare Psize box; Pname varchar2(30);
   begin
     select Dimensions, Product_name into Psize, Pname
             from PRODUCTS where Product_id = 42;
     dbms_output.put_line (’Продукт: ' || Pname);
     dbms_output.put_line (’Размеры: ' || to_char(Psize(1))
                                       || '*' || to_char(Psize(2))
                                       || '*'|| to_char(Psize(3)));
    dbms_output.put_line (’Объем коробочки:’
              || to_char(Psize(1)*Psize(2)*Psize(3)));
 end;

Результаты работы:
Продукт: Торт “Пролет”
Размеры: 12*30*30
Объем: 10800

Рассмотрим более сложный пример коллекций-массивов:

create or replace typeDIM as object(-- новый тип: назв.+3 измерения
   Lbl varchar2(30) – название продукта 
   , Dims box – три измерения
   , member function Pos(Subs in integer)-– измерение в соответств. 
позиции return number , pragma restrict_references (Pos, wnds, wnps, rnps, rnds) , member function Height return number -- высота , pragma restrict_references (Height, wnds, wnps, rnps, rnds) , member function Width return number -- ширина , pragma restrict_references (Width, wnds, wnps, rnps, rnds) , member function Depth return number -- длина , pragma restrict_references (Depth, wnds, wnps, rnps, rnds) , member function Volume return number -- объем , pragma restrict_references (Volume, wnds, wnps, rnps, rnds) );
 create or replace type body Dim is 
    member function Pos (Subs in integer) return number is
    begin
      if Subs > 3 then 
        raise_application_error (-20355,'Неправильная позиция ( >3)');
      end if;
      return self.Dims(Subs);
    end;
    member function Volume return number is -- Возвращает объем
    begin
      -- count – число элементов в массиве
      if Self.Dims.count < 3 then –-Self– обрашение из объекта к себе
       raise_application_error (-20356,’Недостаточно измерений');
      end if;
     return self.Dims(1) * self.Dims(2) * self.Dims(3);
    end;
  member function Height return number is 
       begin return self.Dims(1); end;
  member function Width return number is
       begin  return self.Dims(2);  end;
  member function Depth return number is
       begin return self.Dims(3);   end;
 end;

Создадим таблицу:

create table CAKES ( -- Коробочки с тортами
    No number(6,0) –- Порядковый номер коробочки 
  , Sizes Dim      -- Название торта и размеры коробочки
 );

Вставим три значения в таблицу:

 insert into CAKES values (1,dim(’Пролет',box(2,2,2)));
  insert into CAKES values (2,dim(‘Сказка’,box(3,3,3)));
  insert into CAKES values (3,dim(’Пупочка’,box(4,4,4)));
 commit;

Примеры выборок:

 select C.Sizes.lbl, C.Sizes.volume() FROM CAKES C
   where C.Sizes.volume() > 20;

Возвращает торт #3.

 select * from CAKES C where C.Height() between 2 and 3;
 Возвращает торт #1 и 2.
select * from CAKES C where C.Pos(1) between 2 and 3;

Возвращает то же самое, что и предыдущий.

К сожалению, вложенные массивы пока не поддерживаются

Коллекции – вложенные таблицы (nested tables).

create type project_t as object (
          Pno Number(5)  -- номер проекта
       ,  Pname char(20) –- название проекта
       ,  Budget dec(7,2) – бюджет проекта
 );
create type project_tab_t as table of project_t;

Создадим таблицу отделов, один из столбцов которой является вложенной таблицей проектов:

create table DEPARTMENTS ( 
       Dno Number(3) primary key –- Номер отдела
 ,     Dname char(20) unique     -- название отдела
 ,     Projects project_tab_t )
    nested table Projects store as PROJECT_TABLE;

Рассмотрим механизм занесения данных в таблицу, содержащую вложенную таблицу.

Сначала вставляем строку с пустой вложенной таблицей:

Insert into DEPARTMENTS values (600,’Разработки’, NULL);

Затем инициализируем значение вложенной таблицы для данной строки:

update DEPARTMENTS  set Projects=project_tab_t() where Dno=600;

Ключевое слово the используется для извлечения из стоки вложенной таблицы (должна быть извлечена ровно одна строка):

insert into the (select D.Projects from DEPARTMENT where Dno = 600)
   values (project_t(110, ‘Проект “Мираж”’, 100000));
Commit;
Выбрать все проекты отдела 600 с бюджетом > 10000:
 select N.Pno, N.Pname 
   from THE (select D.projects from DEPARTMENT D
             where D.Dno = 600) N
 where N.Budget > 10000;

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

К сожалению, вложенная таблица не может содержать другую вложенную таблицу.

Коллекции и проектирование схемы данных

Коллекции дают некоторые преимущества перед реляционной структурой:

Приложение 2. Чего нет в Oracle8 Workgroup Edition по сравнению с Enterprise Edition

Workgroup Edition не поддерживает:

Дополнительную информацию Вы можете получить в компании Interface Ltd.

Обсудить на форуме Oracle
Отправить ссылку на страницу по e-mail


Interface Ltd.

Ваши замечания и предложения отправляйте автору
По техническим вопросам обращайтесь к вебмастеру
Документ опубликован: 23.11.00