Oracle9i. Обзор некоторых новых возможностей

Oracle9i. Обзор некоторых новых возможностей.

Ольга Карбасова

Набор продуктов Oracle9i состоит из трех основных компонентов – Oracle9i Database (сервер базы данных), Oracle9i Application Server (сервер приложений) и Oracle9i Developer Suite (средства разработки). В этой статье речь пойдет о нововведениях Oracle9i Database.

Новые возможности Oracle9i Database можно с некоторой долей условности разделить на две группы – предназначенные для разработчиков приложений и для администраторов баз данных. Под разработкой будем подразумевать создание серверной части приложений. 

Разработчику

Исторически сложилось, что при знакомстве с новым продуктом в первую очередь обычно интересуются тем, появились ли какие-то принципиально новые средства и технологии разработки. В Oracle8i такой «революцией» было появление на сервере языка Java как альтернативы PL/SQL. В Oracle9i настолько новых средств разработки серверной части приложений не появилось. Но и новых возможностей старых добрых Java и PL/SQL вполне достаточно, чтобы облегчить процесс создания приложений, а в некоторых случаях изменить технологию разработки.

Сначала рассмотрим новые возможности именно для разработки приложений. Но будем помнить о том, что хорошего разработчика интересуют не только средства разработки («как сделать…»), но и средства оптимизации («…чтобы хорошо работало!»). Кроме того, при установке тиражируемой системы заказчику часто выясняется, что количество пользователей значительно превышает запланированное. Поэтому важно иметь возможность масштабирования системы. 

Развитие SQL главным образом движется в сторону соответствия стандартам. SQL в Oracle9i соответствует требованиям стандарта ISO SQL1999. Для удовлетворения этих требований в язык введено много новых синтаксических конструкций. Это, например, оператор CASE, перекрывающий функциональность старой доброй функции DECODE (в примерах по традиции используются всем известные таблицы Emp и Dept):

SELECT ename "Фамилия",

  (CASE WHEN sal<1000 THEN 'Низкая'

     WHEN sal>4000 THEN 'Высокая'

  ELSE 'Средняя' 

  END) "Зарплата"

  FROM emp;

Изменился и синтаксис соединений. Теперь и в Oracle есть понятия правого/левого/полного внешнего соединения (outer join), например, запрос

select ename, dname from emp right outer join dept 

on (emp.deptno=dept.deptno);

возвращает тот же результат, что и 

select ename, dname from emp, dept

where emp.deptno(+)=dept.deptno;

А вот запрос

select ename, dname from emp full outer join dept 

on (emp.deptno=dept.deptno);

в старом синтаксисе аналога не имеет.

Эти в большинстве своем формально-синтаксические нововведения будут очень полезны при переносе приложений на Oracle с других СУБД. Например, разработчикам легче будет перейти, скажем, с MS SQL на Oracle.

Нововведения в PL/SQL более революционны, они носят гораздо более кардинальный характер. Приверженцам объектной технологии приятно будет узнать, что в объектных типах появилось наследование, принципы которого удовлетворяют стандарту ANSI SQL99. Наследование в Oracle9i строго иерархическое, множественное наследование не допускается. Типы-потомки наследуют у своего родителя атрибуты и методы. Естественно, потомки могут добавлять свои атрибуты и методы, а также и переопределять методы родителя. Пример типа-родителя:

CREATE TYPE Person AS OBJECT

(

 person_id NUMBER,

 date_of_birth DATE,

 name VARCHAR2(30),

 address VARCHAR2(100),



 MEMBER PROCEDURE Hire,         -- может переопределяться

 FINAL MEMBER FUNCTION Age RETURN NUMBER -- не переопределяется

) NOT FINAL;               -- может иметь подтипы

Возможные подтипы:

CREATE TYPE Student UNDER Person 

 (deptid NUMBER, major VARCHAR2(30));  -- добавление атрибутов

CREATE TYPE Employee UNDER Person

 (empid NUMBER, mgr VARCHAR2(30))

 NOT FINAL;

CREATE TYPE PartTimeEmployee UNDER Employee

 (numhours NUMBER);

Вводится и понятие абстрактных (not-instantiable) типов и методов. Разработчик может создавать подтипы таких типов, но не может создавать экземпляры таких типов.

PL/SQL-пакеты можно компилировать в виде разделяемых библиотек. Это устраняет накладные расходы на интерпретацию PL/SQL-кода, что может привести к ускорению выполнения в 2-10 раз. Так что теперь желающие смогут писать функции вычисления интегралов на PL/SQL, не жертвуя при этом производительностью. Конечно, если PL/SQL-программы интенсивно работают с базой данных, значительного выигрыша от компиляции PL/SQL получить не удастся.

В SQL и PL/SQL появились новые типы данных. Особенно оригинален тип AnyData. В столбце этого типа в каждой строке могут храниться данные разных типов (в одной строке – символьные, в другой – числовые, в третьей – структура из двух бинарных и трех числовых полей). Описание типа данных в поле каждой конкретной строки хранится в самом поле. Доступ к данным такого типа пока возможен только через OCI.

Менее оригинальны, но не менее полезны новые типы для даты и времени. Во-первых, тип TimeStamp дает возможность хранить в базе данных дату с точностью до долей секунды (до 9 знаков после запятой). Во-вторых, тип TimeStamp with Time Zone вместе с датой хранит код часового пояса. Сравнение данных этого типа осуществляется с учетом часового пояса. Это очень облегчает работу с распределенными системами и репликацией. Кстати, список стандартных часовых поясов в Oracle9i охватывает весь земной шар. Введены и два принципиально новых типа данных для хранения интервалов времени, не привязанных к конкретной дате – INTERVAL DAY TO SECOND и INTERVAL YEAR TO MONTH. Используя эти типы, удобно задавать, например, продолжительность испытательного срока при приеме на работу:

Create table Jobs(job varchar2(9), trial_period INTERVAL YEAR TO MONTH);

insert into Jobs        -- испытательный срок

 values ('MANAGER','1-6')   -- для менеджера – полтора года;

 select ename, hiredate,

  hiredate + trial_period  -- и когда же он закончится? 

  from emp          -- а вот еще один пример нового

  natural join jobs;     -- синтаксиса соединений 

Поддержка Java интенсивно развивается в направлении соответствия все более новым стандартам. В Oracle9i поддерживаются стандарты Servlet 2.2, JavaServer Pages 1.1, JDBC 2.0.

Отдельно стоит упомянуть и поддержку XML. Введен новый тип данных XMLType, реализованный как LOB, и работа с данными этого типа поддерживается через SQL, PL/SQL и Java.

Идея глобализации нашла свое применение в развитии поддержки многоязыковых баз данных и средств работы с ними, что отражено и в терминологии: термин National Language Support заменен в Oracle9i на Globalization. Среди нововведений в этой области можно выделить новую кодировку для двухбайтного Unicode (UTF16), Unicode на основе кодировки EBCDIC (UTFE) и многоязыковые сортировки. Для облегчения перевода базы данных на новую кодировку предлагается утилита Character Set Scanner. Она сканирует базу данных и определяет, какие столбцы каких таблиц потребуется расширить, и какие символы будут потеряны при переходе. Утилита Locale Builder позволяет модифицировать языковые, территориальные и лингвистические установки (правила сортировки, названия дней и месяцев, правила перевода между верхним и нижним регистрами, форматы даты и т.п.), а также и таблицы кодировки.

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

Известно, что поддержка целостности чтения (read consistency) в Oracle реализована через многоверсионность. Если сессия изменила данные и не зафиксировала (commit) транзакцию, то другие сессии получают старую версию данных. После фиксации транзакции отмена её изменений уже невозможна, а все другие сессии начинают видеть изменённое состояние данных. Поэтому практически невозможно проверить, правильно ли работает какое-нибудь большое пакетное задание типа выставления счетов всем клиентам. Без фиксации транзакций такого рода вещи обычно не обходятся, и если вы обнаружили, что счета выставлены неправильно, отменить уже ничего нельзя, и данные испорчены.

Теперь для подобных тестов можно создать рабочую область и работать в ней. Внутри рабочей области действуют стандартные правила и стандартные алгоритмы поддержания целостности чтения. Пользователь, работающий в своей рабочей области, может делать запросы, изменения данных и фиксировать транзакции. Эти изменения, даже зафиксированные, видны только пользователям, действующим в той же самой рабочей области. После окончания работы с рабочей областью её можно уничтожить, потеряв все изменения в ней, или соединить с основным содержимым базы данных. Так что вышеописанная задача тестирования решается так: создаём рабочую область, переходим в неё, запускаем процедуру, смотрим результат. Если всё правильно – соединяем с основными данными, если нет – уничтожаем рабочую область и ищем ошибку…

Оптимизация приложений

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

Невозможно оставить без внимания ещё одно оригинальное новшество – битовые индексы соединения (bitmap join indexes, BJI). Это обычные битовые индексы, но построенные по столбцам, которых в индексируемой таблице нет. Например, в таблице продаж (назовем её по традиции Sales) есть код региона продажи, но нет его названия. Название есть в справочнике регионов (Regions). В то же время запрос, выбирающий все продажи по региону с заданным названием, довольно типичен. При его выполнении каждый раз требуется соединение (join) таблиц Sales и Regions. Рассмотрим пример.

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

create table Regions 

(

 region_id number primary key,  -- первичный ключ обязателен для создания BJI

 region_name varchar2(200)

);

create table Sales 

(

 id number primary key,

 region_id number,        -- опустим ограничения внешнего ключа

 product_id number,

 amount number, 

 sal_date date

);

Выполним запрос:

Select sum(amount) 

 from sales, regions

 where

    regions.region_id = sales.region_id

  and regions.region_name = 'Центр'

Рассмотрим план выполнения этого запроса (это не единственно возможный, но вполне вероятный план). В плане, естественно, присутствует просмотр обеих таблиц и операция их соединения:

SELECT STATEMENT Optimizer=ALL_ROWS

 SORT (AGGREGATE)

 NESTED LOOPS 

  TABLE ACCESS (FULL) OF 'SALES' 

  TABLE ACCESS (BY INDEX ROWID) OF 'REGIONS'

   INDEX (UNIQUE SCAN) OF 'REGIONS_PK' (UNIQUE)

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

Создадим индекс:

create bitmap index Sales_reg_bji 

 on Sales(regions.region_name)

 from Sales, Regions

 where sales.region_id=regions.region_id

Чтобы побудить оптимизатор использовать этот индекс, применим подсказку (hint). В реальности, если таблицы будут достаточно большими, подсказки скорее всего не понадобятся, т.к. стоимость выполнения этого запроса с использованием индекса будет существенно меньше, чем без него:

select /*+ index(sales sales_reg_bji) */

  sum(amount) from sales, regions 

  where

     regions.region_id  = sales.region_id

   and regions.region_name = 'Центр'

Рассмотрим план выполнения и убедимся, что просмотр таблицы Regions и операция соединения исчезли:

SELECT STATEMENT Optimizer=ALL_ROWS

 SORT (AGGREGATE)

  TABLE ACCESS (BY INDEX ROWID) OF 'SALES' 

   BITMAP CONVERSION (TO ROWIDS)

    BITMAP INDEX (SINGLE VALUE) OF 'SALES_REG_BJI'

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

Real Application Cluster

Технология Real Application Cluster заслуживает отдельной статьи или даже серии статей. Эта технология позволяет перенести приложение, разработанное без учёта особенностей кластерной архитектуры, на кластер, и получить при этом существенное увеличение и производительности, и отказоустойчивости.

Кроме этого к средствам обеспечения масштабируемости можно отнести автоматическое распределение памяти PGA и тонкое распределение ресурсов сервера (развитие технологии Database Resource Manager).

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

Для решения первой проблемы данные нужно сначала извлечь из какого-либо источника (часто этим источником является OLTP-система), потом преобразовать (выполнить денормализацию, просуммировать по какому-либо показателю и т.п.), и потом загрузить в базу данных. Для обозначения этого процесса обычно используется аббревиатура ETL (Extraction, Transformation and Loading).

Одна из основных задач в процессе ETL – определить, какие данные были изменены после последней загрузки хранилища. Технология Change Data Capture позволяет отслеживать все изменения данных, сохранять информацию об изменениях в таблицах изменений (change tables) и просматривать изменения данных за нужный промежуток времени.

Если данные в хранилище загружаются из внешних файлов, то появление внешних таблиц (External Tables) позволяет избежать одного из шагов в ETL-процессе. Внешняя таблица – это таблица, структура которой описана в базе данных, а данные хранятся в плоском файле. В базе данных необходимо описать формат этого файла, для этого используется язык, очень похожий на язык управляющих файлов SQL*Loader. Естественно, внешние таблицы можно использовать только для запросов. Описываются они приблизительно так:

create table emp_external

(

 empno number(4),

 ename char(10),

 job char(9),

 mgr number(4),

 sal number(7,2),

 comm number(7,2),

 deptno number(2)

)

organization external

(

 type oracle_loader         -- другого пока нет

 default directory emp_dir     -- объект типа Directory в базе данных

 access parameters

 (

  fields rtrim

  (

   EMPNO  (01:04),

   ENAME  (06:15),

   JOB   (17:25),

   MGR   (27:30),

   SAL   (32:39),

   COMM   (41:48),

   DEPTNO  (50:51)

  )

 )

 location ('ulcase2.dat')

)

Для облегчения шага Transformation в ETL-процессе предлагаются конвейерные (pipelined) функции. Это функции, которые на входе получают набор строк (ref cursor) и на выходе выдают тоже набор строк (nested table). Их принципиальная новизна в том, что это множество строк они выдают не сразу, а по одной. Внутри такой функции ставится оператор PIPE ROW, который выдает одну строку результата и приостанавливает выполнение функции до тех пор, пока среда, вызвавшая эту функцию (это может быть, например, тоже конвейерная функция), не потребует следующую строку. Рассмотрим пример конвейерной функции.

Объявление типа для источника (producer) данных:

create or replace package emp_pipe is

 type strong_refcur_t is ref cursor return emp%rowtype;

end;

Объявление типа для приемника (consumer) данных:

create or replace type emp_t is

 object (empno number, ename varchar2(10), sal number);

create or replace type emp_t_table as table of emp_t;

Сама конвейерная функция:

create or replace FUNCTION emp_pipe_fun(cur emp_pipe.strong_refcur_t)

 RETURN emp_t_table

 PARALLEL_ENABLE (PARTITION cur BY ANY)

 PIPELINED is

 one_row cur%rowtype;

BEGIN

  LOOP

   FETCH cur INTO one_row;

   /* Здесь можно вставить любую обработку полученной строки */

   EXIT WHEN cur%NOTFOUND;

   /* Оператор PIPE ROW возвращает одну строку результата */

   PIPE ROW (emp_t(one_row.empno, one_row.ename, one_row.sal*10));

 END LOOP;

 CLOSE cur;

 /* RETURN вызывается без аргументов, */

 /* т.к. все результаты функция уже вернула через PIPE ROW */

 RETURN;

END;

Использование этой функции:

select * from table(emp_pipe_fun(cursor(select * from emp)));

Результат работы emp_pipe_fun может послужить источником данных для другой конвейерной функции (назовем ее another_fun):

Select * 

 from table(another_fun(cursor(

   select * from table(emp_pipe_fun(cursor(select * from emp))))));

Это позволяет «нанизывать» такие функции друг на друга и организовывать конвейер преобразования данных.

Новый SQL-оператор Merge и новый многотабличный синтаксис оператора Insert облегчают шаг Loading. Оператор Merge – реализация стандартной для хранилищ данных операции UPSERT, предназначенной для решения задач типа «если продажи в данном регионе уже были – увеличить сумму продаж (Update) по коду региона, если не было – вставить строку с кодом и суммой продаж (Insert)». Например (используем уже упоминавшиеся таблицы Sales и Regions):

Создадим суммарную таблицу продаж по регионам:

create table Sales_sum (region_id number, sum_amount number);

Внесем в нее данные о продажах за последние сутки:

merge into sales_sum SS

 using (select region_id, amount from sales where sal_date>sysdate-1) S

 on (SS.region_id=S.region_id)

 when matched then       -- продажи по региону уже были

  update set SS.sum_amount=SS.sum_amount+S.amount

 when not matched then     -- первая продажа в данном регионе

  insert (SS.region_id, SS.sum_amount)

 values (S.region_id, S.amount);

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

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

create table sales_arch as select * from sales where 0=1;

create table super_sales as select * from sales where 0=1;

Перенесем данные:

insert all

 when amount>100000

  then into super_sales values (id, region_id, product_id, amount, sal_date)

 when 1=1 

  then into sales_arch values (id, region_id, product_id, amount, sal_date)

 select * from sales;

Администратору

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

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

Технология Oracle Data Guard – развитие старой идеи резервной базы данных (Standby Database). Основным недостатком старого варианта была невозможность полного восстановления резервной базы перед ее активизацией. Если при аварии основного сервера повреждался текущий журнал (current redo log), то все изменения базы данных, записанные в этот журнал, терялись безвозвратно. Для многих OLTP-систем это было неприемлемо. Технология Oracle Data Guard позволяет администратору базы данных самому выбрать, что для него важнее – недопущение потери даже самого малого количества данных или максимальная производительность. Если потеря данных недопустима, то можно заставить Oracle отправлять изменения на резервный сервер в синхронном режиме, т.е. пока эти изменения не выполнятся на резервной базе данных, транзакция не считается зафиксированной. Естественно, это может привести к некоторым потерям в производительности. Можно использовать старый метод – изменения передаются на резервный сервер только после заполнения очередного журнала на основном сервере. Тут мы жертвуем сохранностью данных ради производительности. И есть компромиссный вариант – изменения передаются на резервный сервер «почти синхронно», тогда небольшая потеря данных в случае аварии возможна, но маловероятна.

Особого внимания заслуживает новая возможность Recovery Manager – восстановление отдельного блока файла данных. Раньше одним из стандартных способов восстановления при обнаружении поврежденного (corrupted) блока было копирование файла, содержащего этот блок, из резервной копии и применение к нему архивных и оперативных журналов. Это требовало как минимум перевода поврежденного табличного пространства в автономный режим на время копирования файла, что приводило к недоступности части данных на довольно длительный срок. Теперь Recovery Manager может извлечь из резервной копии только поврежденный блок, выполнить его восстановление при помощи журналов и записать восстановленный блок в файл данных. В этом случае временно недоступными оказываются только данные в поврежденном блоке. 

Так называемые возобновляемые операции (Resumable Operations) позволяют бороться с другим очень распространенным видом сбоев – нехваткой пространства в базе данных. Каждый администратор наверняка не раз попадал в ситуацию, когда операция вроде перестроения большого индекса или реорганизации огромной таблицы работает несколько часов и обрывается из-за нехватки места в табличном пространстве (постоянном или временном) или невозможности расширить сегмент отката. В Oracle9i такую операцию можно объявить возобновляемой. Тогда в случае возникновения подобной ошибки процесс не прерывается, а приостанавливается до тех пор, пока администратор не устранит препятствие или не истечет заданный таймаут. Вот как это выглядит.

Создадим таблицу (для чистоты эксперимента – в управляемом системой (dictionary managed) табличном пространстве, т.к. в локально-управляемом (locally managed) не действует параметр Maxextents):

create table Small_extent_table 

 tablespace dict_tbs

 storage (initial 10K maxextents 1)

 as select * from emp;

Несколько раз продублируем в ней данные:

insert into Small_extent_table 

 select * from Small_extent_table;

Примерно на пятой-шестой попытке получим ошибку «ORA-01631: max # extents (1) reached in table SCOTT.SMALL_EXTENT_TABLE». Включим возобновляемые операции (для этого пользователь должен иметь привилегию Resumable):

alter session enable resumable;

Попробуем еще раз:

insert into Small_extent_table 

 select * from Small_extent_table;

Сессия зависает и ждет возможности добавить экстент в таблицу. Из другой сессии обнаружим это:

select name, sql_text, error_msg from dba_resumable;

Получим:

User SCOTT(70), Session 7, Instance 1

insert into small_extent_table s select * from small_extent_table

ORA-01631: max # extents (1) reached in table SCOTT.SMALL_EXTENT_TABLE

Устраним причину ошибки:

alter table Scott.Small_extent_table storage (maxextents 10);

Теперь осталось только убедиться, что в первой сессии оператор Insert успешно закончился.

Еще один классический вид сбоев – ошибки пользователей. Если кто-то из пользователей, разработчиков или сам администратор случайно удалил таблицу или запустил неотлаженную процедуру, восстановить потерянные данные бывает очень трудно. В Oracle8i в таких случаях очень помогает утилита Log Miner. В Oracle9i эта утилита обогатилась новыми возможностями, такими как восстановление текста DDL-операций или возможность пропуска поврежденной части журнала. 

Кроме Log Miner, восстановить данные после пользовательской ошибки помогает еще одно нововведение – ретроспективные запросы (flashback query). С помощью процедур пакета dbms_flashback пользователь может задать нужный момент времени (предшествующий ошибке), и после этого все его запросы будут возвращать состояние данных на указанный момент. Попробуем это сделать.

Удалим важные данные из таблицы:

delete from small_extent_table;

Commit;

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

exec dbms_flashback.enable_at_time(‘05.12.2001 15:21:58')

select * from small_extent_table;

Полученные «старые» данные можно сохранить в базе и ликвидировать последствия ошибки:

declare

 cursor c is (select * from scott.small_extent_table);

 cc c%rowtype;

begin

 exec dbms_flashback.enable_at_time(‘05.12.2001 15:21:58')

 open c;  -- открываем курсор, находясь в режиме FlashBack

 dbms_flashback.disable; -- выключаем FlashBack, чтобы разрешить DML

 loop

  fetch c into cc;

  exit when c%notfound;

  insert into scott.small_extent_table values

   (cc.empno, cc.ename, cc.job, cc.mgr,

    cc.hiredate, cc.sal, cc.comm, cc.deptno);

 end loop;

end;

/

commit;

Естественно, возможность восстановления старого состояния данных ограничена объемом сегментов отката.

У администратора базы данных остается все меньше возможностей повредить базу данных. Не секрет, что одной из наиболее распространенных причин сбоев является ошибочное стирание файла базы данных администратором, например, при удалении табличного пространства. В Oracle9i появились файлы, управляемые сервером Oracle (Oracle Managed Files, OMF). При добавлении файла в базу достаточно указать его размер, а его имя будет сгенерировано Oracle. При удалении файла из базы данных Oracle сам стирает его с диска. Таким образом, с администратора базы данных снимается обязанность манипулировать файлами базы данных, а значит, уменьшается вероятность ошибки.

Жизнь администратора базы данных в Oracle9i вообще заметно облегчена, многие рутинные операции по администрированию Oracle выполняет сам. Динамическое изменение параметров экземпляра и автоматическое управление файлами уже упоминалось. Кроме этого, можно заставить Oracle самостоятельно конфигурировать сегменты отката. Администратор должен только создать специальное табличное пространство для хранения информации отката, а необходимое количество сегментов отката оптимального размера создаст сам Oracle. К тому же администратор может задать, сколько времени Oracle должен сохранять информацию отката даже после фиксации транзакции. Это позволяет если не избавиться от знакомой многим ошибки «ORA-1555: snapshot too old», то существенно снизить вероятность ее проявления. 

Задача переноса данных из одной базы в другую тоже заметно облегчается. Возможность использования переносимых табличных пространств (transportable tablespaces) раньше существенно ограничивалась требованием одинакового размера блока в базе-источнике и базе-приемнике. В Oracle9i в одной базе данных могут сосуществовать табличные пространства с разным размером блока, так что это ограничение снимается. Используя разные размеры блока в одной базе данных, можно оптимально организовать хранение данных различного характера.

Защита от сбоев – важная, но не единственная задача администратора базы данных. Ничуть не менее важна защита данных от несанкционированного доступа. Одно из решений, предлагаемых Oracle9i для защиты данных – виртуальная собственная база данных (Virtual Private Database, VPD). Это развитие технологии детализированного контроля доступа (Fine-Grained Access Control), реализованной в Oracle8i. Как известно, с помощью этой технологии можно было к любой таблице присоединить набор функций, которые срабатывали при каждом запросе или изменении таблицы. Функция возвращала текстовую строку, которая присоединялась к условию WHERE запроса или DML-оператора и таким образом ограничивала набор строк, которые пользователь мог видеть или изменять. Эти функции обычно использовали так называемый контекст приложения (application context). Контекст приложения можно рассматривать как набор переменных, содержащих атрибуты пользователя, такие как должность пользователя, номер его отдела, уровень допуска и т.п. Контекст обычно заполнялся триггером при входе пользователя в базу данных, и функции детализированного контроля доступа использовали атрибуты контекста для того, чтобы определить, к каким данным имеет доступ данный пользователь. 

Эта система хорошо работает в классической клиент-серверной технологии, когда пользователь открывает сессию в базе данных и сохраняет эту сессию за собой. В многоуровневой архитектуре сервер приложений часто открывает в базе данных сразу несколько сессий и затем передает эти сессии работающим через него пользователям. Причем через одну сессию могут работать несколько пользователей, имеющих разные права и уровни допуска, поэтому они должны иметь и разные контексты. В VPD эта проблема решается введением понятия глобального контекста (Global Context) и идентификатора клиента. Теперь в одной сессии в одном контексте может быть несколько одинаковых атрибутов (например, несколько должностей) с разными значениями и разными идентификаторами клиента. Сервер приложений, передавая сессию пользователю, должен установить идентификатор, и пользователь сможет работать со своими значениями атрибутов контекста.

В Oracle9i входит и готовый вариант реализации этой технологии – Oracle Label Security. Это функциональность Trusted Oracle, реализованная средствами VPD. Контроль доступа к строкам основан на системе меток, которые можно назначить каждому пользователю, приложению и строке в таблице. Вся система настраивается через графический интерфейс Oracle Policy Manager, не требуя никакого программирования.

Заключение

Объем одной статьи не позволяет подробно описать все новые средства Oracle9i Database, не говоря уже о других продуктах серии 9i. Поэтому в этой статье мы сосредоточили свое внимание на наиболее интересных на наш взгляд новшествах. В дальнейших материалах мы планируем рассмотреть возможности продукта, не вошедшие в этот обзор.

Все примеры, приведенные в этой статье, были проверены автором на Oracle9i Enterprise Edition Release 9.0.1.1.1 – Production на Windows NT Version 4.0 Service Pack 5.