Oracle Database 12c R2: краткий предварительный обзор новых возможностей
Введение
На момент написания статьи официальный выпуск новой версии Oracle Database 12.2.0.1 еще не состоялся, но уже есть документация и возможность опробовать предварительную версию 12.2.0.1 RC4 от 14.09.2016 в живую в рамках курса Oracle University «Oracle Database 12c R2: New Features for 12c R1 Administrators». Здесь я поделюсь впечатлениями о том, что удалось опробовать и показалось наиболее интересным из этих возможностей.
Контейнерная архитектура
В 12c R2 контейнерная архитектура базы данных получила довольно существенное развитие. Если в 12c R1 удалось реализовать совместное использование компонент инфраструктуры (процессы, память, метаданные) между слабо связанными между собой базами данных, то в 12c R2 через контейнеры приложений появилась возможность совместного использования метаданных и общих данных приложений. С другой стороны появились новые инструменты распределения критичных ресурсов (память, ввод-вывод) между отдельными контейнерами. Архитектура начала приобретать свойство древовидности (с фиксированным количеством уровней).
Как видно из схемы (взята из документации), теперь мы можем в рамках CDB создавать корневые контейнеры приложений и в рамках таких контейнеров новый вид подключаемых баз данных - подключаемых баз данных приложений. Смысл создания нового уровня архитектуры в первую очередь состоит в том чтобы уменьшить стоимость обслуживания однотипных баз данных, характерных для облачных вычислений.
SQL> CREATE PLUGGABLE DATABASE toys_root AS APPLICATION CONTAINER ADMIN USER admin IDENTIFIED BY oracle_4U ROLES=(CONNECT) CREATE_FILE_DEST='/u02/app/oracle/oradata/ORCL/toys_root';
Pluggable database created.
SQL> ALTER PLUGGABLE DATABASE toys_root OPEN;
Pluggable database altered.
Ключевым понятием данного слоя является понятие — Приложение:
· приложения первоначально устанавливаются в корневые контейнеры приложений
· обязательными атрибутами приложения являются его имя и версия
· в рамках инсталляции создаются общие метаданные и данные приложения
· приложения в рамках одного корневого контейнера приложений устанавливаются строго последовательно
· в один контейнер можно разместить несколько приложений
· при первом открытии корневого контейнера создается встроенное приложение с именем APP$GUID, где GUID — это глобальный идентификатор корневого контейнера приложений и для него создается дополнительное логическое имя (или алиас) APP$CON
SQL> SELECT STATEMENT_ID, CAPTURE_TIME, APP_STATEMENT, APP_NAME FROM DBA_APP_STATEMENTS ORDER BY APP_NAME,STATEMENT_ID;
STATEMENT_ID CAPTURE_T APP_STATEMENT APP_NAME
------------ --------- -------------------------------------------------------------------------------- ----------
1 18-DEC-16 SYS APP$43EEE5
DCD146115B
E053AA7AA8
C013FC
2 18-DEC-16 ALTER PLUGGABLE DATABASE APPLICATION APP$CON BEGIN INSTALL '1.0' APP$43EEE5
DCD146115B
E053AA7AA8
C013FC
3 18-DEC-16 ALTER PLUGGABLE DATABASE APPLICATION APP$CON END INSTALL '1.0' APP$43EEE5
DCD146115B
E053AA7AA8
C013FC
· инсталляция приложения начинается с команды ALTER PLUGGABLE DATABASE APPLICATION name BEGIN INSTALL 'version'
· после начала инсталляции приложения начинается захват SQL кода, который выполняется в корневом контейнере приложений в рамках одной или нескольких сессий (так по документации, а пробной версии 12.2.0.1 такой захват в рамках нескольких сессий производился некорректно). Кроме обычного SQL осуществляется захват сессий SQL*Loader. В дальнейшем этот код будет использован при синхронизации PDB приложений с корневым контейнером приложений. Поэтому необходимо, например, избегать указания полного имени файла при создании табличных пространств. При синхронизации будет попытка создания такого же табличного пространства с тем же самым именем файла и синхронизация окончится ошибкой. Посмотреть захваченный SQL код можно в представлении DBA_APP_STATEMENTS:
SQL> SELECT STATEMENT_ID, CAPTURE_TIME, APP_STATEMENT, APP_NAME FROM DBA_APP_STATEMENTS ORDER BY APP_NAME,STATEMENT_ID;
STATEMENT_ID CAPTURE_T APP_STATEMENT APP_NAME
------------ --------- -------------------------------------------------------------------------------- ----------
4 18-DEC-16 SYS TOYS_APP
5 18-DEC-16 ALTER PLUGGABLE DATABASE APPLICATION toys_app begin install '1.0' TOYS_APP
6 18-DEC-16 create user toys_owner identified by VALUES 'S:99933694205B2A9B127C888C8A6A81EC TOYS_APP
7 18-DEC-16 grant create session, dba to toys_owner container=all TOYS_APP
8 18-DEC-16 create table toys_owner.sales_data sharing=metadata TOYS_APP
(year number(4),
regi
9 18-DEC-16 create table toys_owner.codes sharing=object TOYS_APP
(code number(4), label varchar2(10
10 18-DEC-16 insert into toys_owner.codes values (1,'Puppet') TOYS_APP
11 18-DEC-16 insert into toys_owner.codes values (2,'Car') TOYS_APP
12 18-DEC-16 commit TOYS_APP
13 18-DEC-16 ALTER PLUGGABLE DATABASE APPLICATION toys_app end install '1.0' TOYS_APP
· инсталляция приложения заканчивается с командой ALTER PLUGGABLE DATABASE APPLICATION name END INSTALL 'version'. По документации закончить инсталляцию можно в произвольной сессии к корневому контейнеру приложений. Но в пробной версии я натыкался на такое сообщение:
SQL> ALTER PLUGGABLE DATABASE APPLICATION toys_app END INSTALL '1.0';
ALTER PLUGGABLE DATABASE APPLICATION toys_app END INSTALL '1.0'
*
ERROR at line 1:
ORA-65328: cannot end an application action in the current session
· если на момент инсталляции приложения уже существовали другие (не корневые) PDB приложений в этом контейнере, то для того чтобы общие метаданные и данные приложения стали видны в таких PDB, их нужно синхронизировать командой ALTER PLUGGABLE DATABASE APPLICATION … SYNC, подключившись к такой PDB. То же самое относится и к вновь создаваемым PDB при отсутствии в этом корневом контейнере специальной предзаполненной PDB, создаваемой с опцией AS SEED, либо если такая SEED PDB не была предварительно синхронизирована с корневым контейнером. При наличии SEED PDB, другие PDB в этом контейнере приложений создаются как ее клон. Встроенное приложение APP$CON можно синхронизировать, как и любое другое.
· изменить приложение можно операцией Upgrade либо Patch. Разница между операциями состоит в наборе допустимых SQL команд в корневом контейнере после выполнения команды ALTER PLUGGABLE DATABASE APPLICATION … BEGIN [UPGRADE | PATCH]. Крупные изменения обычно оформляются как операция Upgrade, а более мелкие как Patch. При этом в рамках операции Patch недопустимы, например, разрушающие команды (DROP ..). Обе операции меняют версию приложения в корневом контейнере приложений.
· после начала изменения приложения и до команды ALTER PLUGGABLE DATABASE APPLICATION … END [UPGRADE | PATCH] производится такой же захват SQL кода, как и при инсталляции приложения.
· для обеспечения работоспособности существующих некорневых PDB автоматически создается клон корневого контейнера со старой версией приложения.
· если при выполнении SQL кода явно не была начата ни одна из операций Upgrade либо Patch, то считается что изменение относится к встроенному приложению APP$CON и оформляется как операция Patch для него. Может появится искушение не создавать свои приложения, а воспользоваться тем что есть по умолчанию. Но не всегда это может быть возможным — в APP$CON может быть захвачен код, который имеет смысл только для корневого контейнера приложений и оканчивающийся ошибкой в обычной PDB приложений. В примере ниже в APP$CON захвачена операция, которая может быть успешно выполнена (если только в этой PDB уже не был создан локальный пользователь с таким же именем) при синхронизации в любой PDB. Результатом синхронизации будет создание пользователя toys_test в синхронизируемой PDB.
SQL> SELECT STATEMENT_ID, CAPTURE_TIME, APP_STATEMENT, APP_NAME FROM DBA_APP_STATEMENTS ORDER BY APP_NAME,STATEMENT_ID;
STATEMENT_ID CAPTURE_T APP_STATEMENT APP_NAME
------------ --------- -------------------------------------------------------------------------------- ----------
21 18-DEC-16 SYS APP$43EEE5
DCD146115B
E053AA7AA8
C013FC
22 18-DEC-16 ALTER PLUGGABLE DATABASE APPLICATION APP$CON BEGIN PATCH 1 APP$43EEE5
DCD146115B
E053AA7AA8
C013FC
23 18-DEC-16 CREATE USER toys_test IDENTIFIED BY VALUES 'S:54D4AEF3B2DA6B584A0E9C645AFA5320F APP$43EEE5
DCD146115B
E053AA7AA8
C013FC
24 18-DEC-16 ALTER PLUGGABLE DATABASE APPLICATION APP$CON END PATCH 1 APP$43EEE5
DCD146115B
E053AA7AA8
C013FC
· для того чтобы остальные (в том числе и SEED) PDB могли использовать новую версию приложения, их необходимо синхронизировать с корневым контейнером приложений
Кроме пользователей, ролей, профилей и многие другие объекты базы данных, в том числе таблицы и PL/SQL код могут рассматриваться как общие для данного контейнера приложений и создаваться в рамках операций Install, Upgrade и Patch с разными значениями атрибута SHARING:
· METADATA — метаданные такого объекта рассматриваются как общие (принадлежат корневому контейнеру приложений), но данные будут уникальны для каждой PDB (размещаются в них). Это является поведением по умолчанию
· DATA — метаданные и данные такого объекта рассматриваются как общие и размещаются в корневом контейнере приложений, а остальные PDB видят эти метаданные и данные по ссылке
· EXTENDED DATA — метаданные и часть данных принадлежат корневому контейнеру приложений, но каждая из PDB может иметь и собственную порцию данных
· NONE — объект не используется совместно
Мне такая архитектурная конструкция стала напоминать объектную модель таких языков программирования, как Java. Осталось только допустить (сейчас запрещено) вложенность корневых контейнеров приложений друг в друга с возможностью наследования и переопределения метаданных, то мы фактически получили бы иерархию классов не ограниченную как сейчас тремя уровнями. Объекты, разделяемые в режиме DATA могли бы выступать в качестве в качестве статических элементов класса, METADATA как объектные элементы и т. д.
Еще одним вариантом использования контейнерных баз данных, является возможность расщепить большую таблицу на фрагменты и каждый фрагмент обрабатывать независимо от других в своей PDB. А с появлением возможности, которую предоставляют proxy PDB, то и разнести нагрузку по обработке данных на разные контейнерные СУБД, находящихся на разных хостах. Перемещение же PDB с одной контейнерной базы данных в другую контейнерную базу данных тоже в свою значительно упростилось и теперь может быть осуществлено практически без остановки обслуживания пользователей в этой PDB. И если раньше для создания запроса по набору PDB требовалось использование специального синтаксиса с конструкцией CONTAINERS(), то теперь с помощью контейнерных карт можно это сделать не меняя исходный код приложения.
Теперь обо всем по порядку:
· Имеем 2 контейнерные базы данных: CDB1 и CDB2. Подключаемся к ним в разных сессиях и настраиваем SQLPROMPT для удобства:
[oracle@virt05-cdb1 ~]$ . oraenv
ORACLE_SID = [cdb2] ? cdb1
The Oracle base remains unchanged with value /u01/app/oracle
[oracle@virt05-cdb1 ~]$ sqlplus / as sysdba
SQL> set sqlprompt "CDB1> "
CDB1> show pdbs
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
[oracle@virt05-cdb2 ~]$ . oraenv
ORACLE_SID = [cdb2] ? cdb2
The Oracle base remains unchanged with value /u01/app/oracle
[oracle@virt05-cdb2 ~]$ sqlplus / as sysdba
SQL> set sqlprompt "CDB2> "
CDB2> show pdbs
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
· В CDB1 создаем корневой контейнер приложений app_root:
CDB1> create pluggable database app_root as application container
admin user admin identified by oracle_4U roles=(connect) file_name_convert=('pdbseed','app_root');
Pluggable database created.
CDB1> alter pluggable database app_root open;
Pluggable database altered.
CDB1> conn sys/oracle_4U@app_root as sysdba
Connected.
· Инсталлируем приложение app1:
CDB1> alter session set db_create_file_dest='/u01/app/oracle/oradata/cdb1/app_root';
System altered.
CDB1> alter pluggable database application app1 begin install '1.0';
Pluggable database altered.
· При создании табличного пространства используем OMF, иначе мы не сможем выполнить захваченный код в PDB приложений при синхронизации.
CDB1> create tablespace salestbs datafile size 100m autoextend on;
Tablespace created.
CDB1> create user sales_mgr identified by oracle_4U default tablespace salestbs quota unlimited on salestbs container=all;
User created.
CDB1> grant create session,dba to sales_mgr container=all;
Grant succeeded.
· У таблиц будут общими только метаданные, а данные в каждой PDB будут свои
CDB1> create table sales_mgr.regions sharing=metadata
(
region_id number(2) constraint pk_regions primary key,
region_name varchar(30)
);
Table created.
CDB1> create table sales_mgr.sales sharing=metadata
(
region_id number(2) constraint fk_sales_regid references sales_mgr.regions,
sdate date,
ssum number(10, 2)
);
Table created.
CDB1> create index sales_mgr.sales_reg_date_idx on sales_mgr.sales( region_id, sdate );
· Настраиваем возможность создания запросов к таблицам через контейнерную карту. Свойство таблицы containers_default позволяет её использовать во фразе CONTAINERS(table_name) запроса. А свойство container_map позволяет делать отсечку секций (фактически целиком PDB) при выполнении запроса основываясь на ключе секционирования использованном во фразе WHERE. Например WHERE region_id = 2.
CDB1> alter table sales_mgr.regions enable container_map;
Table altered.
CDB1> alter table sales_mgr.sales enable container_map;
Table altered.
CDB1> alter table sales_mgr.regions enable containers_default;
Table altered.
CDB1> alter table sales_mgr.sales enable containers_default;
Table altered.
· Вспомогательную процедуру load_sales, при помощи которой будем заполнять таблицу sales случайными тестовыми данными, тоже сделаем частью приложения:
create or replace procedure sales_mgr.load_sales( p_regid in number )
--sharing=metadata
authid current_user
as
recnum constant pls_integer := 10000;
type datetab is table of sales_mgr.sales.sdate%type index by pls_integer;
type numtab is table of sales_mgr.sales.ssum%type index by pls_integer;
pdates datetab;
pnums numtab;
begin
for i in 1..recnum
loop
pdates(i) := trunc( sysdate - 7 + dbms_random.value * 7, 'DD' );
pnums(i) := dbms_random.value * 10000;
end loop;
forall i in 1..recnum
insert into sales_mgr.sales values ( p_regid, pdates(i), pnums(i) );
commit;
end;
/
· Заканчиваем инсталляцию приложения
CDB1> alter pluggable database application app1 end install '1.0';
· Создаем таблицу контейнерной карты, имена секций в ней должны совпадать с именами PDB приложений, а данные в каждой PDB будут соответствовать своему региону в соответствии с ключом секционирования region_id:
CDB1> create table sales_mgr.maptable
(
region_id number(2),
region_name varchar(30)
) partition by list (region_id)
(
partition europa values (1),
partition asia values (2)
);
· Создадим шаблонную PDB (SEED), на основе которой будут создаваться другие PDB и синхронизируем ее с корневым контейнером приложений
CDB1> create pluggable database as seed admin user admin identified by oracle_4U roles=(connect) file_name_convert=('pdbseed','app_root/app_seed');
Pluggable database created.
CDB1> alter pluggable database app_root$seed open;
Pluggable database altered.
CDB1> conn sys/oracle_4U@app_root$seed as sysdba
Connected.
CDB1> alter session set db_create_file_dest='/u01/app/oracle/oradata/cdb1/app_root/app_seed';
System altered.
CDB1> alter pluggable database application app1 sync;
CDB1> conn sys/oracle_4U@app_root as sysdba
Connected.
CDB1> alter pluggable database app_root$seed close;
Pluggable database altered.
CDB1> alter pluggable database app_root$seed open read only;
Pluggable database altered.
· Теперь можно создать PDB содержащие данные. Они будут создаваться как клон app_root$seed и поэтому их синхронизация с корневым контейнером не понадобиться:
CDB1> !mkdir -p /u01/app/oracle/oradata/cdb1/app_root/europa
CDB1> create pluggable database europa admin user admin identified by oracle_4U
roles=(connect) create_file_dest='/u01/app/oracle/oradata/cdb1/app_root/europa';
Pluggable database created.
CDB1> !mkdir -p /u01/app/oracle/oradata/cdb1/app_root/asia
CDB1> create pluggable database asia admin user admin identified by oracle_4U
roles=(connect) create_file_dest='/u01/app/oracle/oradata/cdb1/app_root/asia';
Pluggable database created.
CDB1> alter pluggable database europa open;
Pluggable database altered.
CDB1> alter pluggable database asia open;
Pluggable database altered.
· Заполним данными наши таблицы и соберем статику по ним. Статистика по общим объектам собирается по месту нахождения данных.
CDB1> conn sales_mgr/oracle_4U@europa
Connected.
CDB1> insert into regions values ( 1, 'Europa' );
1 row created.
CDB1> commit;
Commit complete.
CDB1> exec load_sales( 1 )
PL/SQL procedure successfully completed.
CDB1> exec dbms_stats.gather_table_stats(null, 'regions', cascade => true, method_opt => 'FOR ALL COLUMNS SIZE AUTO' )
PL/SQL procedure successfully completed.
CDB1> exec dbms_stats.gather_table_stats(null, 'sales', cascade => true, method_opt => 'FOR ALL COLUMNS SIZE AUTO' )
PL/SQL procedure successfully completed.
CDB1> conn sales_mgr/oracle_4U@asia
Connected.
CDB1> insert into regions values ( 2, 'Asia' );
1 row created.
CDB1> commit;
Commit complete.
CDB1> exec load_sales( 2 )
PL/SQL procedure successfully completed.
CDB1> exec dbms_stats.gather_table_stats(null, 'regions', cascade => true, method_opt => 'FOR ALL COLUMNS SIZE AUTO' )
PL/SQL procedure successfully completed.
CDB1> exec dbms_stats.gather_table_stats(null, 'sales', cascade => true, method_opt => 'FOR ALL COLUMNS SIZE AUTO' )
PL/SQL procedure successfully completed.
· Устанавливаем таблицу maptable в качестве контейнерной карты:
CDB1> conn sys/oracle_4U@app_root as sysdba
Connected.
CDB1> alter database set container_map='sales_mgr.maptable';
Database altered.
· Теперь запрос сделанный из корневого контейнера приложений должен вернуть данные из обеих PDB без использования фразы CONTAINERS, а таблицы содержать псевдостолбец CON_ID. Проверяем:
CDB1> conn sales_mgr/oracle_4U@app_root
Connected.
CDB1> alter session set statistics_level=all;
CDB1> select * from regions;
REGION_ID REGION_NAME CON_ID
---------- ------------------------------ ------
2 Asia 5
1 Europa 4
· Создадим консолидированный отчет и посмотрим план выполнения такого запроса:
CDB1> select region_name, sdate, count(*), sum(ssum)
from regions natural join sales
group by region_name, sdate
order by region_name, sdate;
REGION_NAME SDATE COUNT(*) SUM(SSUM)
------------------------------ --------- ---------- ----------
Asia 26-DEC-16 670 3394452.92
Asia 27-DEC-16 1481 7439305.88
Asia 28-DEC-16 1394 6904729.47
Asia 29-DEC-16 1376 6770055.16
Asia 30-DEC-16 1471 7502937.79
Asia 31-DEC-16 1403 7223986.58
Asia 01-JAN-17 1421 6991020.73
Asia 02-JAN-17 784 3920130.94
Europa 26-DEC-16 682 3406421.12
Europa 27-DEC-16 1415 7238801.51
Europa 28-DEC-16 1416 6949857.66
Europa 29-DEC-16 1496 7507359.6
Europa 30-DEC-16 1413 7048534.64
Europa 31-DEC-16 1464 7374674.52
Europa 01-JAN-17 1405 6904727.33
Europa 02-JAN-17 709 3529188.03
16 rows selected.
Теперь посмотрим как можно перемещать наши PDB в другие контейнерные базы данных не изменяя код приложения создающий консолидированную отчетность. Это может понадобиться, например, при исчерпании ресурсов на данном сервере или для того чтобы сбалансировать нагрузку по серверам. Переносить будем PDB asia в CDB2. Для этого на понадобиться сделать клон корневого контейнера app_root на CDB2, а на CDB1 создать proxy PDB, которая будет прозрачно для приложения перенаправлять запросы на другую базу данных через Database Link. Обе базы данных должны работать в режиме локального UNDO и архивирования журнальных файлов.
· Склонируем корневой контейнер приложений app_root с CDB1 на CDB2 под именем app_rr:
oracle@virt05-cdb2 ~]$ sqlplus / as sysdba
SQL> set sqlprompt "CDB2> "
CDB2> create public database link link_cdb1 connect to system identified by oracle_4U using 'CDB1';
Database link created.
CDB2> alter session set db_create_file_dest='/u02/app/oracle/oradata/cdb2/app_rr';
Session altered.
CDB2> create pluggable database app_rr as application container from app_root@link_cdb1;
Pluggable database created.
CDB2> alter pluggable database app_rr open;
Pluggable database altered.
· На CDB1 создадим proxy PDB для перенаправления запросов на CDB2:
CDB1> conn sys/oracle_4U@app_root as sysdba
Connected.
CDB1> !mkdir -p /u01/app/oracle/oradata/cdb1/app_root/px_app_rr
CDB1> create public database link link_cdb2 connect to system identified by oracle_4U using 'CDB2';
Database link created.
CDB1> alter session set db_create_file_dest='/u01/app/oracle/oradata/cdb1/app_root/px_app_rr';
Session altered.
CDB1> create pluggable database px_app_rr as proxy from app_rr@link_cdb2;
Pluggable database created.
CDB1> alter pluggable database px_app_rr open;
Pluggable database altered.
· Для перемещения PDB мы должны дать на базе источнике привилегию SYSOPER пользователю, через которого работает Database Link на приемнике:
CDB1> conn / as sysdba
Connected.
CDB1> grant sysoper to system container=all;
Grant succeeded.
· Готовим базу данных приемник:
CDB2> conn sys/oracle_4U@app_rr as sysdba
Connected.
CDB2> create public database link link_cdb1 connect to system identified by oracle_4U using 'CDB1';
Database link created.
CDB2> !mkdir -p /u01/app/oracle/oradata/cdb2/app_rr/asia
CDB2> alter session set db_create_file_dest='/u01/app/oracle/oradata/cdb2/app_rr/asia';
· Перемещаем PDB asia на CDB2:
CDB2> create pluggable database asia from asia@link_cdb1 relocate;
Pluggable database created.
· В данный момент PDB2 asia у нас присутствует на обеих CDB. На CDB1 она открыта на чтение/запись, а на CDB2 она закрыта:
CDB2> show pdbs
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
3 APP_RR READ WRITE NO
5 ASIA MOUNTED
CDB1> show pdbs
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
3 APP_ROOT$SEED READ WRITE NO
4 EUROPA READ WRITE NO
5 ASIA READ WRITE NO
6 APP_ROOT READ WRITE NO
7 PX_APP_RR READ WRITE NO
· Но при первом открытии на чтение/запись PDB asia в CDB2, на старом месте в CDB1 её автоматически закроют и удалят. При необходимости, можно было бы воспользоваться режимом AVAILABILITY MAX, чтобы не обрывать существующие сессии пользователей к перемещаемой PDB.
CDB2> alter pluggable database asia open;
Pluggable database altered.
CDB2> show pdbs
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
3 APP_RR READ WRITE NO
5 ASIA READ WRITE NO
CDB1> show pdbs
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
3 APP_ROOT$SEED READ WRITE NO
4 EUROPA READ WRITE NO
6 APP_ROOT READ WRITE NO
7 PX_APP_RR READ WRITE NO
· Осталось проверить что наш запрос создания консолидированной отчетности по прежнему работает:
CDB1> conn sales_mgr/oracle_4U@app_root
Connected.
CDB1> select region_name, sdate, count(*), sum(ssum)
from regions natural join sales
group by region_name, sdate
order by region_name, sdate;
REGION_NAME SDATE COUNT(*) SUM(SSUM)
------------------------------ --------- ---------- ----------
Asia 26-DEC-16 670 3394452.92
Asia 27-DEC-16 1481 7439305.88
Asia 28-DEC-16 1394 6904729.47
Asia 29-DEC-16 1376 6770055.16
Asia 30-DEC-16 1471 7502937.79
Asia 31-DEC-16 1403 7223986.58
Asia 01-JAN-17 1421 6991020.73
Asia 02-JAN-17 784 3920130.94
Europa 26-DEC-16 682 3406421.12
Europa 27-DEC-16 1415 7238801.51
Europa 28-DEC-16 1416 6949857.66
Europa 29-DEC-16 1496 7507359.6
Europa 30-DEC-16 1413 7048534.64
Europa 31-DEC-16 1464 7374674.52
Europa 01-JAN-17 1405 6904727.33
Europa 02-JAN-17 709 3529188.03
16 rows selected.