Oracle 12c. Новые фичи приносят новые подводные камни

от автора

Всем привет.

Разбирая новые возможности Oracle 12c, то тут, то там сталкиваюсь с подводными камнями, когда не всё работает так, как ожидалось, падает или просто не очевидно. Конечно, это стандартная ситуация когда в первом релизе новой версии много сырого… но, как известно, предупреждён — значит вооружен. Вероятно, кому-то пригодится, чтобы не повторять мои грабли.

Пишу грабли в порядке наступления на них.

Знакомим PMON с локальным listener

Начнём с простого, что даже не совсем бага, а вопрос конфигурирования.
Инсталлировали в стандартной установке и настройке Oracle 12c (в моём случае — на Oracle Linux, но, думаю, не критично).
— Создаём CDB базу.
— Поключаем/создаём PDB-базы.
По-умолчанию добавленные базы не видится listener-ом. «Из коробки» PMON не подружился с listener-ом, живущим на том же сервере и автоматическая регистрация не происходит. Не трагедия, однако руками добавлять записи в listener.ora, как-то совсем не интересно в контексте новой фичи multitenant architecture.
Давайте познакомим PMON и локально живущий listener:

ALTER SYSTEM SET local_listener='(ADDRESS = (PROTOCOL=TCP)(HOST=192.168.56.101)(PORT=1521))' scope=both; ALTER SYSTEM REGISTER; 

База зарегистрировалась, listener увидел, радость наступила. Нельзя сказать что это особенность именно 12-ки, но именно в ней появилась возможность буквально на ходу добавлять / управлять базами, и в рамках Multitenant architecture автоматическая регистрация баз в listener, как никогда актуальна. Раньше создание новой базы было намного большим «событием» и добавить пару строк в listener.ora не вызывало у меня каких-либо предубеждений.

Автозапуск PDB после перезагрузки

Перезапускаем сервер. CDB поднялась. PDB — не открыты (при подключении ошибка database shutdown or startup in progress).
Не знаю, может это и правильно, что после перезагрузки сервера администратор должен подключиться к CDB базе и сказать

alter pluggable database all open; 

Вроде как просто так базы не перезагружаются (не должны)… Но что-то мне подсказывает, что это, мягко говоря, не удобно. А DBA, которые поддерживают десятки и сотни баз одновременно — явно спасибо не скажут.
Настройки или команды которая бы убедила Оракл что автостартовать PDB-шки всё таки нужно, не обнаружилось (может плохо искал. Подскажите в коммантариях если кто нашёл).
Во всезнающем интернете этот момент уже давно не новость и наиболее распространённая рекомендация:

create or replace trigger open_all_pdb after startup on database  BEGIN       execute immediate 'alter pluggable database all open';  END open_all_pdbs; 

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

Invisible columns

Особенность не Оракла, а PL/SQL developer-а (версия10.0.1.1694 — скачан с сайта PL/SQL Developer-а буквально недавно), но всё же.
Сравним поведение на невидимой колонке sqlplus (ведёт в соответсвии с документацией):

SQL> descr test_invisible;  Name                     Null?    Type  ------------------ -------- -----------  ID                             NUMBER(38)  THIRD_COL                     NUMBER(38) 

И PL/QSL Developer command window:

SQL> descr test_invisible; Name      Type         Nullable Default Comments  --------- ------------ -------- ------- --------  ID        INTEGER      Y                          THIRD_COL INTEGER      Y                          INV_COL   VARCHAR2(20) Y                          

Не знает пока что Pl/Sql developer про новую фичу, что не удивительно. Но не все осознают что command window у PL/SQL-девелопера — это не честный sql*plus через какой-нибудь pipe, а просто псевдо-подобный интерфейс.
Думаю скоро образумятся, но в первый момент несколько удивился и задумался.

PL/SQL support in with

Как утверждает Оракл, эта фича была сделана в первую очередь для поднятия производительности (детальное рассмотрение фичи оставим за скобками, ибо оффтопик к теме поста), как и умолчим, что pragma UDF работает в этих целях не хуже, но…
«НО» заключается в баге обнаруженном Johnathan Lewis и описанном в его блоге.
Добавиви одну performance «фичу» поламали (в некоторых случаях) — другую — DETERMINISTIC.

Рассмотрим на примере кода:

-- Создали для примера таблицы с данными только из единичек. CREATE TABLE all_ones AS SELECT 1 AS ID FROM dual CONNECT BY LEVEL<100;  SET TIMING ON ARRAYSIZE 15  WITH   FUNCTION slow_function(p_id IN NUMBER) RETURN NUMBER DETERMINISTIC IS   BEGIN DBMS_LOCK.sleep(1); RETURN p_id; END; SELECT slow_function(ID) FROM   all_ones WHERE  ROWNUM <= 10; / …. 10 rows selected. Elapsed: 00:00:10.02 

Хотя, справедливости ради, проявляется это не во всех случаях:

WITH FUNCTION slow_function(p_id IN NUMBER)  RETURN NUMBER DETERMINISTIC IS BEGIN    DBMS_LOCK.sleep(1);    RETURN p_id;  END; SELECT slow_function(1) FROM   all_ones WHERE  ROWNUM <= 10; / 10 rows selected. Elapsed: 00:00:01.01  WITH FUNCTION slow_function(p_id IN NUMBER) RETURN NUMBER DETERMINISTIC IS BEGIN    DBMS_LOCK.sleep(1);    RETURN p_id;  END; SELECT (SELECT slow_function(id) FROM dual) FROM   all_ones WHERE  ROWNUM <= 10; / Elapsed: 00:00:01.02 
SQL Text expansion

Ещё одно приятное нововведение — новая процедура DBMS_UTILITY.EXPAND_SQL_TEXT — я её уже описывал раньше на хабре.
Когда её испытывал, она замечательно отработала как на моих view и таблицах с VPD…, так и к примеру, на all_users… однако попытка применить её к all_objects привела к ошибке в пакете dbms_utility. Предполагаю, причина в том, что даже у пользователя с ролью DBA не обнаружилось доступа к каким-то совсем внутренним системным объектам… а может просто баг в коде.

DECLARE x CLOB; BEGIN   dbms_utility.expand_sql_text(input_sql_text => 'select * from all_objects', output_sql_text => x );   dbms_output.put_line(x); END; ORA-00904: : invalid identifier ORA-06512: at "SYS.DBMS_UTILITY", line 1581 ORA-06512: at line 3 

И вот ещё пара вещей, с которыми столкнулся не сам, но тоже было интересно почитать у других:

DBMS_METADATA and session sequence

Найдено в одной из тем на sql.ru.
Похоже, DBMS_METADATA пока что не в курсе про новую фичу:

-- создадим сессионный sequence create sequence seq session;  DECLARE   x CLOB; begin   x:=dbms_metadata.get_ddl( 'SEQUENCE', 'SEQ');   dbms_output.put_line(x); end; /  -- Получаем обычный seqence, без аттрибута session. Так вот. CREATE SEQUENCE  "DENKREP"."SEQ"  MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER  NOCYCLE  NOPARTITION; 
Pagination, массивы и run-time расчёт количества строк для fetch

Нашёл у человека в блоге

 SQL> declare   2      type table_tt is table of employees%rowtype;   3      v_tt table_tt;   4   5      v_limit_nr number:=10;   6      v_counter_nr number:=0;   7  begin   8      select *   9      bulk collect into v_tt  10      from employees  11      offset v_counter_nr*v_limit_nr rows  12      fetch next v_limit_nr rows only; -- variable   13  end;  14  /     type table_tt is table of employees%rowtype;                               * ERROR at line 2: ORA-03113: end-of-file on communication channel Process ID: 3060 Session ID: 20 Serial number: 35307 SQL>  -- Причём если прописать количество получаемых строк явно, то всё работает.   ...   12      fetch next 10 rows only; -- hard-code  13  end;  14  / PL/SQL procedure successfully completed. SQL> 

PS: В комментариях к источнику написали что о баге оракл уже знает и на металинке заведён bug #17404511

Пока что всё. Надеюсь было интересно.

ссылка на оригинал статьи http://habrahabr.ru/post/196350/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *