ORACLE MAGAZINE
Июль Поиск
Российское Электронное Издание

Общая методология
Новости и события
Опыт пользователей
Oracle Applications
Высокие технологии
Постоянная экспозиция
Мастерская разработчика
Кабинет администратора
Полезные ссылки
Архив







       КАБИНЕТ АДМИНИСТРАТОРА

Log Miner в Oracle: Часть 2

1 июля 2000 г.

Дэрил Хели, Mobile Data Solutions

Источник http://www.revealnet.com/newsletter/logminer_part_2.doc
04 марта 2000

Содержание первой части

В первой части приводилось общее представление о работе Log Miner и о запуске сеанса исследования содержимого журнальных файлов. Мы закончили непосредственным просмотром такого содержимого. Во второй части рассмотрим подробнее, из чего оно состоит, и как его можно использовать.

V$-представления в Log Miner

Все действия Log Miner регистрируются в четырех динамических V$-представлениях («таблицах»), описываемых далее.

V$LOGMNR_DICTIONARY

В этом представлении содержится информация словаря-справочника Log Miner, указанного аргументом DICTFILENAME при вызове DBMS_LOGMNR.START_LOGMNR. Как мы помним, файл словаря-справочника помогает перевести содержимое журнальных файлов из зашифрованного вида в читаемый текст.

Вот какую информацию несет в себе это представление:

TIMESTAMP                DATE
Дата и время создания файла со словарем.
DB_ID                    NUMBER
Идентификатор БД, для которой был создан словарь.
DB_NAME                  VARCHAR2(8)
Имя БД, для которой был создан словарь.
FILENAME                 VARCHAR2(513)
Имя файла со словарем, включая каталог.
DICTIONARY_SCN           NUMBER
SCN базы данных на время создания
файла со словарем.
RESET_SCN                NUMBER
SCN сброса журнала на время создания
файла со словарем.
RESET_SCN_TIME           DATE
Время установки SCN на момент создания
файла со словарем.
ENABLED_THREAD_MAP       RAW(16)
Поразрядная карта активных нитей Oracle на
время создания файла со словарем.
STATUS                   NUMBER
Если ноль, то файл со словарем согласован
с загруженными журнальными файлами.
Если не ноль, то дополнительную информацию
см. в поле INFO.
INFO                     VARCHAR2(32)
Если NULL, то файл со словарем-справочником
согласован с загруженными журнальными
файлами.  В противном случае здесь
приводится поясняющая информация.

V$LOGMNR_LOGS

В этом представлении содержится информация о журнальных файлах, загруженных в Log Miner. Загрузка осуществляется с помощью DBMS_LOGMNR.ADD_LOGFILE.

Представление содержит следующую информацию:

LOG_ID                   NUMBER
Идентификатор журнального файла.
FILENAME                 VARCHAR2(513)
Имя журнального файла, включая каталог.
LOW_TIME                 DATE
Дата/время самой старой записи в журнальном файле.
HIGH_TIME                DATE
Дата/время самой последней записи в журнальном файле.
DB_ID                    NUMBER
Идентификатор БД-владелицы журнального файла.
DB_NAME                  VARCHAR2(8)
Имя БД-владелицы журнального файла.
RESET_SCN                NUMBER
SCN «сброса» (reset) журнального файла, момента,
когда он был создан.
RESET_SCN_TIME           DATE
Время «сброса» журнального файла, когда образовался
SCN, представленный в поле REST_SCN.
THREAD_ID                NUMBER
Номер процессной нити.
THREAD_SQN               NUMBER
Номер последовательности.
LOW_SCN                  NUMBER
SCN, при котором произошло переключение на журнал.
NEXT_SCN                 NUMBER
SCN для следующего журнального файла.
STATUS                   NUMBER
Ноль означает, что журнальный файл в работоспособен
(valid). Если не ноль, поясняющую информацию смотри
в поле INFO.
INFO                     VARCHAR2(32)
Поясняющая информация, если STATUS не равно нулю.

V$LOGMNR_PARAMETERS

В этом представлении собраны записи о параметрах работающего в текущий момент сеанса исследования. Это те параметры, которые задаются при вызове DBMS_LOGMNR.START_LOGMNR.

Представление содержит следующую информацию:

START_DATE               DATE
Дата/время старта сеанса исследования.
END_DATE                 DATE
Дата/время окончания сеанса исследования.
START_SCN                NUMBER
Стартовый SCN для сеанса исследования.
END_SCN                  NUMBER
Конечный SCN для сеанса исследования.
STATUS                   NUMBER
Состояние сеанса исследования.  Ноль означает 
нормальное рабочее состояние;  если не ноль
- дополнительную информацию смотри в поле INFO.
INFO                     VARCHAR2(32)
Дополнительная информация о состоянии сеанса
исследования, если поле STATUS не равно нулю.

V$LOGMNR_CONTENTS

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

SCN                       NUMBER
SCN, связанный с изменением записи.
TIMESTAMP                 DATE
Дата/время изменения записи.
THREAD#                   NUMBER
Номер процессной нити, в рамках которой было
выполнено изменение.
LOG_ID                    NUMBER
Идентификатор ID журнального файла, 
зарегистрировавшего изменение.
SEG_OWNER                 VARCHAR2(32)
Владелец сегмента.
SEG_NAME                  VARCHAR2(32)
Имя сегмента.
SEG_TYPE                  NUMBER
Тип сегмента.
SEG_TYPE_NAME             VARCHAR2(32)
Тип сегмента при использовании объектов.
TABLE_SPACE               VARCHAR2(32)
Имя табличного пространства.
ROW_ID                    VARCHAR2(19)
Идентификатор ID строки.
SESSION#                  NUMBER
Номер сеанса.
SERIAL#                   NUMBER
Последовательный номер сеанса.
USERNAME                  VARCHAR2(32)
Имя пользователя.
SESSION_INFO              VARCHAR2(4000)
Произвольная информация о сеансе.
ROLLBACK                  NUMBER
Запрос на использование сегмента отката.
OPERATION                 VARCHAR2(32)
Выполненная операция.  Может быть:
COMMIT
DELETE
INSERT
UPDATE
INTERNAL
START
Первые четыре - стандартные операции DML.
INTERNAL указывает, что операция была
выполнена самой СУБД, а START указывает
на выдачу команду старта транзакции, например
на SET TRANSACTION.
SQL_REDO                  VARCHAR2(4000)
Код SQL для повторения операции снова;
приводится с ROWID.
SQL_UNDO                  VARCHAR2(4000)
Код  SQL для отмены результата выполнения
операции; приводится с ROWID.
STATUS                    NUMBER
Состояние операции.
INFO                      VARCHAR2(32)
Дальнейшая информация о состоянии операции.
PH1_NAME                  VARCHAR2(32)
PH1_REDO                  VARCHAR2(4000)
PH1_UNDO                  VARCHAR2(4000)
PH2_NAME                  VARCHAR2(32)
PH2_REDO                  VARCHAR2(4000)
PH2_UNDO                  VARCHAR2(4000)
PH3_NAME                  VARCHAR2(32)
PH3_REDO                  VARCHAR2(4000)
PH3_UNDO                  VARCHAR2(4000)
PH4_NAME                  VARCHAR2(32)
PH4_REDO                  VARCHAR2(4000)
PH4_UNDO                  VARCHAR2(4000)
PH5_NAME                  VARCHAR2(32)
PH5_REDO                  VARCHAR2(4000)
PH5_UNDO                  VARCHAR2(4000)
В сером прямоугольнике приведены столбцы,
используемые для отображения столбцов;
об этом будет сказано ниже.

Исследование журналов из архива

Архивированные журналы исследуются так же, как и оперативные. Они подгружаются в перечень файлов для исследования той же процедурой, что и оперативные журналы, то есть процедурой DBMS_LOGMNR.ADD_LOGFILE. А вот определение параметров начала и окончания для процедуры DBMS_LOGMNR.START_LOGMNR требует определенных навыков. Сейчас мы дополним пакет из первой части кодом, который будет это делать. Ниже приводится новый заголовок пакета.

Воспользуемся логикой исследования журналов по диапазону времени и добавим код, задающий временной промежуток, и код, загружающий этот промежуток. Чтобы определить, какой именно журнальный файл загрузить, воспользуемся другой V$-таблицей, V$ARCHIVED_LOG.

CREATE OR REPLACE PACKAGE miner AS

/*
||
|| MINER
||
|| В этом пакете используется DBMS_LOGMNR
||
|| ТРЕБОВАНИЯ : Oracle 8.1.5 или выше
|| SELECT ANY TABLE
|| EXECUTE ON SYS.DBMS_LOGMNR
||
*/

PROCEDURE load_online;
PROCEDURE clear_list;
PROCEDURE start_miner;
PROCEDURE stop_miner;
PROCEDURE set_dict( p_dict_file VARCHAR2 );
PROCEDURE set_start_date ( p_start_date DATE );
PROCEDURE set_end_date ( p_end_date DATE );
PROCEDURE load_archived;

END miner;

Как видно, добавлено три новых процедуры, SET_START_DATE, SET_END_DATE и LOAD_ARCHIVED, код которых следует ниже.

/*-----------------------------------------*/
PROCEDURE set_start_date ( p_start_date DATE ) IS
/*-----------------------------------------*/

КОММЕНТАРИЙ : v_start_date - переменная пакета

BEGIN
v_start_date := p_start_date;
END set_start_date;

/*-----------------------------------------*/
PROCEDURE set_end_date ( p_end_date DATE ) IS
/*-----------------------------------------*/

КОММЕНТАРИЙ : v_end_date - переменная пакета

BEGIN
v_end_date := p_end_date;
END set_end_date;

/*-----------------------------------------*/
PROCEDURE load_archived IS
/*-----------------------------------------*/

КОММЕНТАРИЙ : Этот курсор позволяет получить все заархивированные журнальные файлы в заданном диапазоне времени.

CURSOR curs_get_logs ( cp_start DATE,
cp_end DATE ) IS
SELECT name,
first_change#,
next_change#
FROM v$archived_log
WHERE first_time BETWEEN cp_start
AND cp_end
AND archived = 'YES'
AND deleted = 'NO';

BEGIN

FOR v_arch_rec IN curs_get_logs(v_start_date,v_end_date) LOOP

КОММЕНТАРИЙ : Для первого журнального файла используем NEW; для остальных - ADDFILE

IF curs_get_logs%ROWCOUNT = 1 THEN
SYS.DBMS_LOGMNR.ADD_LOGFILE(TRIM(v_arch_rec.name),
SYS.DBMS_LOGMNR.NEW);
ELSE
SYS.DBMS_LOGMNR.ADD_LOGFILE(TRIM(v_arch_rec.name),
SYS.DBMS_LOGMNR.ADDFILE);
END IF;

v_start_scn := LEAST(NVL(v_start_scn,v_arch_rec.first_change#),
v_arch_rec.first_change#);
v_end_scn := GREATEST(NVL(v_end_scn,v_arch_rec.first_change#),
v_arch_rec.next_change#);

END LOOP; -- все заархивированные файлы найдены

КОММЕНТАРИЙ : v_end_scn содержит первый SCN следующего журнального файла, поэтому чтобы он не вышел за диапазон SCN этого файла, уменьшим его на единицу.

v_end_scn := v_end_scn - 1;

END load_archived;

Теперь можно проверить, что мы сделали, например таким образом:

SQL> EXEC miner.set_start_date (SYSDATE - 10);

PL/SQL procedure successfully completed.

SQL> EXEC miner.set_end_date(SYSDATE - 5);

PL/SQL procedure successfully completed.

SQL> EXEC MINER.load_archived;

PL/SQL procedure successfully completed.

Осталось только выставить имя файла со словарем и запустить сеанс исследования, и все пойдет как надо. Детали смотри в части I.

Изучение содержимого представлений Log Miner

Найти необходимые сведения по представлению V$LOGMNR_CONTENTS достаточно просто. Вот некоторые примеры возможных запросов.

В: Сколько вставок записей выполнил Henderson?
О: Просто укажите имя пользователя и операцию в запросе ниже.

SELECT COUNT(*)
FROM v$logmnr_contents
WHERE username = 'HENDERSON'
AND operation = 'INSERT';

В: Что следует выполнить, чтобы отменить все вставки записей, выполненные Henderson?
О: Запрос тот же, только выбирать нужно поле SQL_UNDO

SELECT sql_undo
FROM v$logmnr_contents
WHERE username = 'HENDERSON'
AND operation = 'INSERT';

В: Какие изменения в поле зарплаты в таблице сотрудников вносил HR?
О: Для начала можно выдать примерно такой запрос:

SELECT sql_redo
FROM v$logmnr_contents
WHERE seg_owner = 'HR'
AND seg_name = 'EMPLOYEE';

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

Отображение столбцов

Механизм отображения столбцов позволяет просто отслеживать конкретные изменения значений полей в таблице. В части I этой статьи я уже упоминал о параметре OPTIONS процедуры DBMS_LOGMNR.START_LOGMNR. Если вы заметили, тогда я его полностью проигнорировал. Я сделал это по двум причинам: во-первых, хотел отложить подробное обсуждение до части II, а во-вторых, я не мог тогда заставить этот параметр заработать! Но об этом потом, а сейчас о том, как можно пользоваться отображением столбцов.

Использование

Отображение столбцов активизируется присвоением константы Log Miner USE_COLMAP аргументу OPTIONS процедуры DBMS_LOGMNR.START_LOGMNR:

BEGIN
DBMS_LOGMNR.START_LOGMNR(
startscn => 1000000,
endscn => 2000000,
dictfilename => 'my_file',
options => SYS.DBMS_LOGMNR.USE_COLMAP);
END;

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

Файл отображения столбцов

Повторю: отображение столбцов используется для отслеживания конкретных изменений данных в конкретных столбцах конкретных таблиц. Такие изменения в данных будут видны в таблице V$LOGMNR_CONTENTS в полях с PH1 до PH5, так мило оттененных серым цветом выше по тексту.

Файл с отображением столбцов - обычный текстовый файл, расположенный в том же каталоге, что и файл со словарем-справочником Log Miner. Называется файл просто: logmnr.opt, а вот синтаксис файла уже не так прост.

Файл отображения столбцов имеет очень четкий синтаксис, требующий весьма точного соблюдения, иначе файл работать не будет. Когда он работает, жизнь прекрасна, когда же нет, - ужасна: отлаживать файл нельзя, поскольку никаких сообщений об ошибках не выдается!

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

CREATE TABLE employee
(empno NUMBER,
salary NUMBER);

Теперь, в соответствии с теорией, что первые сотрудники в компании получают больше всего денег, заполним таблицу некоторыми данными.

SQL> BEGIN
2 FOR x IN 1..10 LOOP
3 INSERT INTO employee
4 VALUES(x,(100 - x) * 10000);
5 END LOOP;
6 COMMIT;
7 END;
8 /

PL/SQL procedure successfully completed.

SQL> select *
2 from employee;

    EMPNO    SALARY
--------- ---------
        1    990000
        2    980000
        3    970000
        4    960000
        5    950000
        6    940000
        7    930000
        8    920000
        9    910000
       10    900000

Теперь составим файл отображения столбцов. Напомню, что это текстовый файл, и его можно редактировать редактором типа Notepad. Для того, чтобы следить за изменением столбца с зарплатой в таблице сотрудников, в первой строке файла укажем в точности следующее: colmap = SYSTEM EMPLOYEE (1, SALARY);

Предложение выше состоит из следующих компонент:

ключевое слово colmap
Говорит о том, что строка задает отображение столбца. После него должен идти пробел.
оператор равенства
После него должен идти пробел.
имя владельца объекта
Имя владельца отображаемого объекта. За именем должен следовать пробел.
имя объекта
Имя отображаемого объекта. За ним должен идти пробел.
открывающая скобка
Обозначает начало перечня столбцов (их можно указывать более одного).
номер столбца
Номер столбца, в который будет осуществляться отображение. Может принимать значение от 1 до 5.
запятая
Должна следовать за номером столбца, а следом за ней должен идти пробел.
имя столбца
Имя столбца, для которого будет строиться отображение.
закрывающая скобка
Обозначает конец перечисления столбцов (если их несколько).
точка с запятой
Должна следовать за закрывающей скобкой.

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

SQL> UPDATE employee
2 SET salary = salary + 100
3 WHERE empno = 1;

1 row updated.

SQL> COMMIT;
Commit complete.

Вот как мы можем посмотреть в V$LOGMNR_CONTENTS точные значения изменений:

SQL> SELECT sql_redo,
2 sql_undo,
3 ph1_name,
4 ph1_redo,
5 ph1_undo
6* FROM v$logmnr_contents

SQL_REDO
-------------------------------------------------------------------------------
SQL_UNDO
-------------------------------------------------------------------------------
PH1_NAME PH1_REDO PH1_UNDO
---------- ---------- ----------
update SYSTEM.EMPLOYEE set SALARY = 990100 where ROWID = 'AAABGpAABAAABdQAAA';
update SYSTEM.EMPLOYEE set SALARY = 990000 where ROWID = 'AAABGpAABAAABdQAAA';
SALARY 990100 990000

1 row selected.

Обратите внимание, что столбец PH1_NAME содержит столбец, указанный нами в файле отображения (logmnr.opt), а столбец PH1_UNDO содержит предыдущее значение, а столбец PH1_REDO содержит новое значение. То есть нам сообщается, что значение столбца SALARY было изменено с 990000 на 990100. Мы можем уточнить изменение дальше и выяснить конкретную строку (и создать, таким образом, систему аудита), воспользовавшись столбцом ROWID в таблице V$LOGMNR_CONTENTS.

А что происходит при обновлении группы строк? Рад, что вы об этом спросили. Дадим теперь прибавку всем сотрудникам (но не такую высокую, как основателю!)

SQL> UPDATE employee
2 SET salary = salary + 99.99
3 WHERE empno <> 1;

9 rows updated.

SQL> commit;

Commit complete.

Все 9 модифицированных строк будут видны в V$LOGMNR_CONTENTS следующим образом (не забудьте, что мы должны будем начать новый сеанс исследования):

SQL> SELECT sql_redo,
3 sql_undo,
4 ph1_name,
5 ph1_redo,
6 ph1_undo
7* FROM v$logmnr_contents;

SQL_REDO
----------------------------------------------------------------------------------------------------
SQL_UNDO
----------------------------------------------------------------------------------------------------
PH1_NAME PH1_REDO PH1_UNDO
---------- ---------- ----------
update SYSTEM.EMPLOYEE set SALARY = 980099.99 where ROWID = 'AAABGpAABAAABdQAAB';
update SYSTEM.EMPLOYEE set SALARY = 980000 where ROWID = 'AAABGpAABAAABdQAAB';
SALARY 980099.99 980000

update SYSTEM.EMPLOYEE set SALARY = 970099.99 where ROWID = 'AAABGpAABAAABdQAAC';
update SYSTEM.EMPLOYEE set SALARY = 970000 where ROWID = 'AAABGpAABAAABdQAAC';
SALARY 970099.99 970000

update SYSTEM.EMPLOYEE set SALARY = 960099.99 where ROWID = 'AAABGpAABAAABdQAAD';
update SYSTEM.EMPLOYEE set SALARY = 960000 where ROWID = 'AAABGpAABAAABdQAAD';
SALARY 960099.99 960000

update SYSTEM.EMPLOYEE set SALARY = 950099.99 where ROWID = 'AAABGpAABAAABdQAAE';
update SYSTEM.EMPLOYEE set SALARY = 950000 where ROWID = 'AAABGpAABAAABdQAAE';
SALARY 950099.99 950000

update SYSTEM.EMPLOYEE set SALARY = 940099.99 where ROWID = 'AAABGpAABAAABdQAAF';
update SYSTEM.EMPLOYEE set SALARY = 940000 where ROWID = 'AAABGpAABAAABdQAAF';
SALARY 940099.99 940000

update SYSTEM.EMPLOYEE set SALARY = 930109.99 where ROWID = 'AAABGpAABAAABdQAAG';
update SYSTEM.EMPLOYEE set SALARY = 930010 where ROWID = 'AAABGpAABAAABdQAAG';
SALARY 930109.99 930010

update SYSTEM.EMPLOYEE set SALARY = 920099.99 where ROWID = 'AAABGpAABAAABdQAAH';
update SYSTEM.EMPLOYEE set SALARY = 920000 where ROWID = 'AAABGpAABAAABdQAAH';
SALARY 920099.99 920000

update SYSTEM.EMPLOYEE set SALARY = 910099.99 where ROWID = 'AAABGpAABAAABdQAAI';
update SYSTEM.EMPLOYEE set SALARY = 910000 where ROWID = 'AAABGpAABAAABdQAAI';
SALARY 910099.99 910000

update SYSTEM.EMPLOYEE set SALARY = 900099.99 where ROWID = 'AAABGpAABAAABdQAAJ';
update SYSTEM.EMPLOYEE set SALARY = 900000 where ROWID = 'AAABGpAABAAABdQAAJ';
SALARY 900099.99 900000

Снова мы получаем полный аудит всех изменений столбца SALARY таблицы EMPLOYEE. Механизм отображения столбцов можно использовать для построения полной системы аудита. Более полную информацию, и в том числе полное описание синтаксиса файла отображения столбцов, можно найти в документации по Oracle.

Применения технологии Log Miner

Базы данных Standby/Backup/Reporting

Пакеты Log Miner в значительной степени представляют собой API к standby-технологии Oracle для баз данных (базы горячего резерва). Log Miner может исследовать журнальные файлы не только текущей базы Oracle, но и любой другой. Таким образом, появляется возможность применять транзакции, регистрируемые в журналах одной базы данных Oracle, к другой базе. Эта вторая база может служить целям горячего резерва (standby), резервирования от потерь (backup), а также составления отчетов (reporting).

Аудит изменений

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

Сбор статистики о производительности

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

Странности поведения и нестыковки

Log Miner, как и всякая новая технология, временами являет странности своего поведения. Кое-что из того, что я встретил по этой части, описано ниже:

Переключения журналов и оперативные журнальные файлы

Когда Log Miner исследует оперативные журнальные файлы и происходит переключение с одного журнального файла на другой, Log Miner начинает вести себя неадекватно. Иногда в таких случаях в V$LOGMNR_CONTENTS пропадают все записи, а иногда только некоторые. В этом не просматривается ни какой-нибудь закономерности, ни причины.

Правильность файла отображения столбцов

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

Ошибки START_LOGMNR

Неправильное указание каких-нибудь параметров в DBMS_LOGMNR.START_LOGMNR приводит к достаточно темному сообщению ORA-1280 Fatal Log Miner Error. Причины для такого сообщения могут быть самые разные, и, будем надеяться, в следующих версиях Log Miner появятся более информативные сообщения.

Об авторе

Дэрил Хели занимается администрированием и разработкой на Oracle в течение 10 лет. Кроме активной деятельности в рубрике Pipeline на узле фирмы RevealNet, он еще работает старшим АБД в фирме Mobile Data Solutions в солнечном Канадском Ванкувере. Он также по совместительству консультирует в Ванкувере и окрестностях от имени фирмы ImpleStrat Solutions. Ему хотелось бы принести извинения перед читателями, не входящими в число поклонников древнегреческой мифологии, а возможно и перед поклонниками. Ему можно написать по адресам dhurley@mdsi.bc.ca и implestrat@yahoo.com.



Материал номера:
Новый тест для специалистов по Oracle


Колонка главного редактора:

Oracle открывает третье тысячелетие.

 Письмо в редакцию
 


Человек месяца: Беседа с руководителями ИВЦ АИС и WEB-центра “Омега”
Oracle: от МВД до РПЦ