среда, 9 октября 2019 г.

EXCEPTION (Обработка ошибок)


PL/SQL блок:

DECLARE
...  -- объявляющая секция
BEGIN
...  -- выполняющая секция
EXCEPTION
...  -- секция обработки исключительных ситуаций
END;
/


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

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

Исключения бывают:

- стандартные
- определенные пользователем

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

Исключительные ситуации, определяемые пользователем,
устанавливаются явно при помощи оператора RAISE.


Обрабатываются исключения так:

EXCEPTION
    WHEN имя_ex1 THEN
        ...; -- обработать
    WHEN имя_ex2 THEN
        ...; -- обработать
    WHEN OTHERS THEN
        ...; -- обработать
END;
/


Имена исключений не должны повторяться т.е. каждое исключение может
обрабатываться максимум только одним обработчиком в секции EXCEPTION

Один обработчик может обслуживать несколько исключительных ситуаций
и их нужно перечислить в условии WHEN через OR

EXCEPTION
    WHEN NO_DATA_FOUND OR TOO_MANY_ROWS THEN
        INSERT INTO log_table(info) VALUES ('A select error occurred.');
END;
/

Два исключения одновременно один обработчик обработать не может:

WHEN имя_ex1 AND имя_ex2  - > ERR



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

DECLARE
    e_my_ex EXCEPTION;
    ...
BEGIN
    IF (...) THEN
        RAISE e_my_ex;
    END IF;
    ...

EXCEPTION
    WHEN e_my_ex THEN
    ...
END;
/



После перехвата более специализированных исключений:

WHEN ... THEN
...
WHEN ... THEN

мы можем перехватить все остальные исключения с помощью:

WHEN OTHERS THEN
...


Обработчик OTHERS рекомендуется помещать на самом высоком уровне программы:
(В самом высшем блоке)
для обеспечения распознавания всех возможных ошибок.

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

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

WHEN OTHERS THEN NULL;

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

Обработчик OTHERS должен регистрировать ошибку и возможно предоставлять
дополнительную информацию для дальнейшего исследования.

WHEN OTHERS THEN
    INSERT INTO log_table(info) VALUES ('Another error occurred.');
END;
/

Информацию об ошибках можно получить при помощи двух встроенных функций:

- SQLCODE
- SQLERRM

первая возвращает код текущей ошибки а вторая текст сообщения об ошибке

Для исключений определенных пользователем:

SQLCODE возвращает 1
а
SQLERRM "User-defined Exception"



WHEN OTHERS THEN
    v_ErrorCode := SQLCODE;
    v_ErrorText := SUBSTR(SQLERRM, 1, 200);
    INSERT INTO log_tab(code, message, info) VALUES (v_ErrorCode, v_ErrorText, 'Oracle error.');
END;
/

В таблице log_tab поле message ограничено 200 символами
и чтобы не произошло ошибки при вставке, мы урезаем длину
сообщения до 200 символов с помощью SUBSTR
А то максимальная длина сообщения может достигать 512 символов.

Функция SQLERRM может принимать один числовой аргумент.
При этом она возвратит текст сообщения об ошибке, код которой равен заданному числу.

Аргумент должен быть всегда отрицательным числом.
Если аргумент равен 0, то будет возвращено сообщение:
ORA-0000: normal, succesful completion

При положительном аргументе не равном 100 будет возвращено сообщение:
non-ORACLE Exception

А при

SQLERRM(100) - > ORA-1403: no data found

Это исключение ANSI

Остальные коды ошибок Oracle все отрицательные.

Для получения информации об ошибке можно также использовать функцию
FORMAT_ERROR_STACK из пакета DBMS_UTILITY

Её можно непосредственно использовать в операторах SQL:

WHEN OTHERS THEN
    INSERT INTO log_tab(code, message, info) VALUES (NULL,
                                                     SUBSTR(DBMS_UTILITY.FORMAT_ERROR_STACK, 1, 200),
                                                    'Oracle error occurred.');
END;
/


Ещё одна функция.

DBMS_UTILITY.FORMAT_ERROR_BACKTRACE

она аналогична  FORMAT_ERROR_STACK
но не подвержена ограничению длины сообщения в 2000 байт.
Она возвращает полностью весь стек ошибок на момент инициирования исключительной ситуации.

Любое именованное исключение можно связать с конкретной ошибкой ORACLE.

Например, в ORACLE есть стандартная ошибка ORA-1400, которая возникает при пропуске значения
или вставке значения NULL в столбец с ограничением NOT NULL.

ORA-1400: mandatory NOT NULL column missing or NULL during insert.

Мы хотим создать свое пользовательское именованное исключение и связать его с этой стандартной ошибкой ORA-1400

DECLARE
e_my_ex EXCEPTION;
PRAGMA EXCEPTION_INIT(e_my_ex, -1400);

BEGIN
WHEN e_my_ex THEN
    INSERT INTO log_tab(info) VALUES ('ORA-1400 occurred.');
END;
/

Теперь мы перехватываем её по имени с помощъю WHEN или THEN

Все стандартные исключительные ситуации также ассоциируются с соответствующими им ошибками Oracle
при помощи прагмы EXCEPTION_INIT в пакете STANDARD


VALUE_ERROR  - > ORA-6501
TO_MANY_ROWS - > ORA-1422
ZERO_DIVIDE  - > ORA-1476
..........
и т.д.


Так что если вам не хватает некоего имени конкретной ошибки ORA-NNNN,
то придумайте свое имя и свяжите его с ошибкой с помощью прагмы : EXCEPTION_INIT


Для собственных пользовательских исключений можно придумать свои коды ошибок, которые разрешено брать из диапазона:
-20000 до -20999
и придумать свой текст сообщения


RAISE_APPLICATION_ERROR(номер, текст, [флаг]);

TRUE - пополнить список ранее произошедших ошибок
FALSE - новая ошибка заместит текущий список ошибок (по умолчанию)


set serveroutput on

variable a NUMBER;
variable b NUMBER;

exec :a := 0;
exec :b := 10;

DECLARE
    l_a NUMBER := :a;
    l_b NUMBER := :b;
    l_c NUMBER;

BEGIN
    IF l_a = 0 THEN
        raise_application_error(-20005, 'Divizor is 0');
    END IF;
    l_c := l_b / l_a;
    dbms_output.put_line('The result: '||l_c);
EXCEPTION
    WHEN OTHERS THEN
        dbms_output.put_line(SQLERRM);
END;
/


Поскольку у исключения нет имени, то его может обработать только обработчик OTHERS

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

DECLARE

    my_ex EXCEPTION;
    .....
    .....
    PRAGMA EXCEPTION_INIT(my_ex, -20005);

BEGIN
    IF (...) THEN
        raise_application_error(-20005, 'Divizor is 0');
    .....
    .....

EXCEPTION
    WHEN my_ex THEN
        dbms_output.put_line(SQLERRM);
END;
/


Теперь это исключение можно обработать по имени с помощью:

WHEN my_ex THEN


EXCEPTION PROPAGATION


enclosing block  - обьемлющий блок

Если в текущем блоке имеется обработчик данной исключительной ситуации,
то он выполняется и блок успешно завершается.
Управление передаётся вышестоящему блоку.

Если обработчик отсутствует, исключительная ситуация передается в обьемлющий блок и инициируется там.
Если обьемлющего блока не существует, то исключение будет передано вызывающей среды (например SQL*Plus).


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

BEGIN

    p(...); -- вызов процедуры
EXCEPTION
    WHEN OTHERS THEN
        -- исключение инициированное p()
        -- будет обработано здесь
END;
/




Исключения инициируемые в секции обьявлений (DECLARE) не обрабатываются секцией EXCEPTION
текущего блока, а передаются в EXCEPTION обьемлющего блока.

Тоже самое, если исключение инициируется в секции EXCEPTION,
то обработка данного исключения передается в обьемлющий блок.

Исключительную ситуацию можно обработать в текущем блоке и сразу снова установить
то же самое исключение, которое будет передано в обьемлющую область:


DECLARE

    A EXCEPTION;
BEGIN

    RAISE A;
EXCEPTION
    WHEN A THEN
        INSERT INTO log_tab(info) VALUES ('Exception A occurred.');
        COMMIT;
        RAISE;
END;
/


Тут commit гарантирует, что результаты insert будут зафиксированы
в базе данных в случае отката транзакции.

С помощью пакета UTL_FILE можно избежать необходимости commit
или используйте автономные транзакции.


Область действия исключительной ситуации


BEGIN
    DECLARE
        e_ex EXCEPTION;  -- видно по имени только внутри блока
    BEGIN
        RAISE e_ex;
    END;
EXCEPTION
    -- тут исключение не видно по имени e_ex
    -- и его можно обработать с помощью обработчика OTHERS

    WHEN OTHERS THEN
        -- инициируем это исключение повторно
        RAISE;  -- Теперь это исключение передается вызывающей среде
END;
/

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

Как описать исключение, которое будет видно вне блока?

Нужно создать пакет Globals и описать в нем пользовательское исключение.
Такая исключительная ситуация будет видима и во внешнем блоке.

CREATE OR REPLACE PACKAGE Globals AS
    e_ex EXCEPTION;
END Globals;

BEGIN
    BEGIN
        RAISE Globals.e_ex;
    END;

EXCEPTION
    WHEN Globals.e_ex THEN
        -- инициируем повторно
        -- для передачи в вызывающую среду
        RAISE;
END;
/
 

В пакете Globals можно также объявлять:

- таблицы
- переменные
- типы


Избегайте необработанных исключений
Нельзя допускать завершение программ, пока в них остаются необработанные исключения

Используйте обработчик OTHERS на самом верхнем уровне программы.
И пусть он регистрирует факт и время возникновения ошибки.
И ни одна ошибка не останется без внимания.

DECLARE

    v_ErrorNumber NUMBER;
    v_ErrorText   VARCHAR2(200);
BEGIN
    ...
    ...

EXCEPTION
    WHEN OTHERS THEN
        ...

        v_ErrorNumber := SQLCODE;
        v_ErrorText   := SUBSTR(SQLERRM, 1, 200);

        INSERT INTO log_tab(code, message, info)
        VALUES (v_ErrorNumber, v_ErrorText,
                'Oracle error ...at ' || to_char(sysdate, 'DD-MON-YYHH24:MI:SS'));
END;
/


Можно использовать и утилиту  DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
она регистрирует первоначальное местовозникновения исключения.

Как определить, где произошла ошибка?

BEGIN

    SELECT ...
    SELECT ...
    SELECT ...
EXCEPTION
    WHEN NO_DATA_FOUND THEN
    -- какой select инициировал ошибку?
END;
/

Можно создать счетчик, указывающий на sql - оператор:


DECLARE

    v_sel_count NUMBER := 1;
BEGIN

    SELECT ...
    v_sel_count := 2;
    SELECT ...
    v_sel_count := 3;
    SELECT ...

EXCEPTION
    WHEN NO_DATA_FOUND THEN
        INSERT INTO log_tab(info)
        VALUES ('no data found in select '||v_sel_count);
END;
/


Можно разместить каждый select в собственном врутреннем блоке

BEGIN

    BEGIN
        SELECT ...
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            INSERT INTO log_tab(info)
            VALUES ('no data found in select 1');
    END;


    BEGIN
        SELECT ...
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            INSERT INTO log_tab(info)
            VALUES ('no data found in select 2');
    END;


    BEGIN
        SELECT ...
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            INSERT INTO log_tab(info)
            VALUES ('no data found in select 3');
    END;

END;
/


Или использовать : DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
и потом анализировать файл трассировки.




Пусть в нашей программе Oracle выдает ошибку ORA-01844: not f valid month

перехватить его можно так:

EXCEPTION
    WHEN OTHERS THEN
        IF SQLCODE = -1843 THEN


Да, код плохо читаем.
Сделаем его более лучшим:

PROCEDURE my_procedure
IS
    invalid_month EXCEPTION;
    PRAGMA EXCEPTION_INIT(invalid_month, -1843);

BEGIN
    ....
EXCEPTION
    WHEN invalid_month THEN

так уже более понятней.





вторник, 24 сентября 2019 г.

Ассоциативные массивы

Ассоциативные массивы

Ассоциативные массивы могут быть определены только в рамках программы PL/SQL
Ни структура массива, ни данные не могут сохраняться в БД.

Каждый элемент массива отличается индексом:

Индексирование с помощью binary_integer:

1 | ...........
2 | ...........
3 | ...........

...............
10 | ...........


Индексирование с помощью varchar2:

a | ...........
b | ...........
c | ...........

...............
z | ...........

Они впервые появились в Oracle 7 и назывались по разному:

Oracle 7  - таблицы PL/SQL
Oracle 8  - индекс таблицы
Oracle 10 - ассоциативные массивы

Объявляются они так:

type name is table of type [not null]
index by type;

Тип индекса может быть:

- binary_integer
- pls_integer
- positive
- natural
- signtype
- varchar2

Тип данных элемента может быть:
- number и его подтипы
- varchar2 и его подтипы
- date
- blob
- clob
- boolean

А также:

- типы данных наследуемые из столбца таблицы
- курсорного выражения
- предопределённой переменной модуля
- определённый пользователем тип объекта или коллекции

Пример:

type clob_t is table of clob
index by pls_integer;

type empno_t is table of employees.empno%type not null
index by employees.ename%type;


Пример ассоциативного массива:

declare

type ln is table pers.f_name%TYPE
index by pls_integer;

begin

fam(20) := 'Tom';
fam(15) := 'Larry';
fam(-10) := 'Scott';

l_row := fam.FIRST;
while (l_row is not null)  loop
    dbms_output.put_line(fam(l_row));
    l_row := fam.NEXT(l_row);
end loop;

end;
/


Ещё пример:

set serveroutput on

declare

type str_t is table of number
index by varchar2(10);

l_str str_t;
l_idx varchar2(50);

begin

l_str('JAN-MAR') := 90;
l_str('APR-JUN') := 91;
l_str('JUL-SEP') := 92;
l_str('OCT-DEC') := 93;

l_idx := l_str.FIRST;
while (l_idx is not null) loop
    dbms_output.put_line('Value at index ' || l_idx || 'is' || l_str(l_idx));
    l_idx := l_str.NEXT(l_idx);
end loop;
end;
/


Следующий PL/SQL блок объявляет ассоциативный массив для хранения ASCII значений чисел от 1 до 100:

set serveroutput on

declare

type ascii_t is table of varchar2(12)
index by pls_integer;

l_get_ascii ascii_t;

begin

for i in 1 .. 100 loop
    l_get_ascii(i) := ascii(i);
end loop;

dbms_output.put_line(l_get_ascii(5));
end;
/

53



Ассоциативные массивы :

- не могут быть использованы в таблицах и применяются только как программные структуры
- не требуют инициализации (нет метода EXTEND)
- индексы: только строки и числа
  (положительные, отрицательные и нуль)

- неявно конвертируются из:
 %ROWTYPE
 типов записи
 объектных типов
- не могут применяться в транзакциях DML (как непостоянные коллекции)
- могут передаваться как аргумент другим локальным подпрограммам в рамках одного и того-же блока.
- ассоциативный массив, объявленный в спецификации модуля, ведет себя как массив, постоянный внутри сессии.
в структуры ассоциативных массивов

- являются ключом к использованию оператора FORALL
  или фразы BULK COLLECT
которые разрешают групповую пересылку данных из БД в программный модуль.

Если в качестве индекса используется индексная строка, то порядок их обработки
зависит от параметров БД:
NLS_SORT
NLS_COMP

Пример:

DECLARE

type card is table of varchar2(5 char)
index by binary_integer;

-- конструктор использовать нельзя
cards card := card('A', 'B', 'C');
-- error 00222

-- объявим переменную
cards card;

BEGIN

-- нельзя перемещаться по ассоциативному массиву,
-- пока в нём отсутствуют элементы
dbms_output.put_line(cards(1));
-- error no data found

END;
/


Чтобы избежать подобной ошибки делайте так:

DECLARE

type card is table of varchar2(5 char)
index by binary_integer;

cards card;

BEGIN

if cards.COUNT < > 0 then
    dbms_output.put_line(cards(1));
else
    dbms_output.put_line('cards coll is empty.');
end if;

END;
/


Метод COUNT возвращает нулевое значение только:
- когда у ассоциативного массива отсутствуют элементы с присиоенными значениями.
- когда varray или nested table проинициализпрованы и их элементам не выделена память

Метод EXTEND не сможет выделить память для ассоциированного массива


DECLARE

type card is table of varchar2(5 char)
index by binary_integer;

cards card;

BEGIN

if cards.COUNT < > 0 then
    dbms_output.put_line(cards(1));
else
    cards.EXTEND;
-- error 00306
end if;

END;
/



Инициализация ассоциативных массивов

DECLARE

type mv is varray(12) of varchar2(9 char);

type calt is table of varchar2(9 char)
index by binary_integer;

month mv := mv('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');

calendar calt;

-- тут month - это varray
-- calendar - это ассоциативный массив

BEGIN
if calendar.COUNT = 0 then
    dbms_output.put_line('Assigment loop:');
    dbms_output.put_line('---------------');
    for i in month.FIRST .. month.LAST LOOP
        calendar(i):= '';
        -- инициализируем
        dbms_output.put_line('Index[' || i || '] is [' calendar(i) || ']');
        calendar(i) := month(i);
    end loop;

    dbms_output.put_line(chr(10));
    dbms_output.put_line('Post-assigment loop:');
    dbms_output.put_line('--------------------');

    for i in calendar.FIRST .. calendar.LAST LOOP
        dbms_output.put_line('Index[' || i || '] is [' calendar(i) || ']');
    end loop;
end if;

END;
/




Числовой индекс:

type mv is varray(12) of string(9 char);

type calt is table of varchar2(9 char)
index by binary_integer;

month mv := mv('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');

calendar calt;
   
calendar(1) := '';
calendar(1) := month(1);

calendar(1) := 'January';

-- calendar(1) - > January



Строковый индекс:

type mv is varray(12) of string(9 char);

type calt is table of varchar2(9 char)
index by varchar2(9 char);

month mv := mv('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');

calendar calt;
   
calendar(January) := '1';
.....
calendar(December) := '12';


calendar(April) - > 4
.....
calendar(September) - > 9


Для строкового индекса процесс изменяется:

-- Присвоим значения:
if calendar.COUNT = 0 then
    for i in month.FIRST .. month.LAST LOOP
        calendar(month(i)):= i;
    end loop;


-- Вывод значений:
    for i in calendar.FIRST .. calendar.LAST LOOP
        dbms_output.put_line('Index[' || i || '] is [' calendar(i) || ']');
    end loop;
end if;

Инициализация сработает
А второй цикл for при выводе значений выдаст ошибку

calendar(April) - > 4
.....
calendar(September) - > 9


При попытке вызвать функции FIRST и LAST мы получим ORA-06502
Ошибка преобразования числа

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

Для нечисловых значений индексов необходимо знать с чего следует начинать и как наращивать.

Методы FIRST и NEXT дают нам такое средство

Рассмотрим логику обхода уникальных строковых индексов.

Определим две переменные, которые будут использованы для управления навигацией
по ассоциативному массиву с уникальными строковыми индексами

current varchar2(9 char);
element integer;

Цикл по всем элементам фссоциативного массива:

for i in 1 .. calendar.COUNT loop

    -- проверьте, является ли элемент первым в списке
    if i = 1 then
        -- присвойте первый символьный индекс переменной
        current := calendar.FIRST;

        -- используйте полученный индекс для нахождения следующего индекса
        element := calendar(current);
    else
        -- проверьте существует ли следующее значение индекса
        if calendar.NEXT(current) is not null then

            -- присвойте символьный индекс переменной
            current := calendar.NEXT(current);

            -- используйте полученный индекс для нахождения следующего индекса
            element := calendar(current);
        else
            exit
            -- было прочитано последнее значение индекса
        end if
    else if

    dbms_output.put_line('Index[' || current || '] is [' element || ']');

end loop;



Метод FORALL

Есть таблица t1  с полем id типа number.

Обычная вставка данных:

begin

for i in 1 .. 10000 loop
    insert into t1 values(i);
end loop;
commit;
end;
/

Вставка данных из коллекции:

begin

forall i in 1 .. num_list.COUNT
    insert into t1 values(num_list(i));
commit;
end;
/

Метод FORALL позволяет посылать операторы DML пакетами

Метод FORALL предлагает средство для переноса содержимого ассоциативного массива
или вложенной таблицы в объект БД.

declare

type td is table of t1.id%type
index by binary_integer;

num_list td;

begin

for i in 1 .. 10000 loop
    insert into t1 values(i);
end loop;


forall i in 1 .. num_list.COUNT
    insert into t1 values(num_list(i));
commit;
-- фиксируем результат каждого пакета вставок
end;
/


Метод BULK COLLECT

Метод BULK COLLECT позволяет выбирать наборы записей ,
которые можно хранить в массивах переменной длины и во вложенных таблицах.

Метод BULK COLLECT позволяет, как единое множество,
присвоить коллекцию значений %ROWTYPE или %TYPE ассоциативному массиву
или вложенной таблице.

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

Память во вложенной таблице будет неявно выделять bulk collect

Для ассоциированного массива не требуется конструктора,
достаточно группового присваивания.

Выборка данных в ассоциативный массив:

declare

type td is table of t1.id%type
index by binary_integer;

num_list td;

begin

select id bulk collect into num_list from t1 order by 1;

for i in num_list.FIRST .. num_list.LAST loop
    if i < = 2  or i > = 9999 then
        dbms_ounput.put_line(num_list(i));
    end if;
end loop;
end;
/


четверг, 20 сентября 2018 г.

План запроса

При реальном выполнении запроса, во время hard parse, происходит peeks bind values.
Explain plan и SQL*Plus autotrace - do not peek bind values, когда они порождают планы.

А также Explain plan и SQL*Plus autotrace не учитывают преобразование типов данных.
Например, если столбец символьного типа сравнивается с числом, происходит неявное
преобразование типов и индекс столбца не может использоваться.


Получить реальный план выполнения запроса можно из представления v$sql_plan.

Определяем hash_value, address, child_number, sql_id, plan_hash_value

SELECT hash_value, address, child_number, sql_id, plan_hash_value
FROM v$sql
WHERE  sql_text LIKE '%select sysdate from dual%'
AND sql_text NOT LIKE '%v_sql%';


Получить план можно так:


По hash_value:

SELECT
   lpad(' ', 2 * level) || pt.operation || ' ' || pt.options || ' ' || pt.object_name "Plan Access Path",
   pt.cost,
   pt.cardinality,
   pt.bytes,
   pt.cpu_cost,
   pt.io_cost,
   pt.temp_space,
   pt.access_predicates,
   pt.filter_predicates,
   pt.qblock_name as "Query Block name"
FROM (select *
             from v$sql_plan
             where HASH_VALUE = 2343063137
             and ADDRESS =  '00007FF7C88C4128'
             and  CHILD_NUMBER = 0
           ) pt
CONNECT BY PRIOR pt.id = pt.parent_id
START WITH pt.id = 0;


Или по sql_id:

SELECT
   lpad(' ', 2 * level) || pt.operation || ' ' || pt.options || ' ' || pt.object_name "Plan Access Path",
   pt.cost,
   pt.cardinality,
   pt.bytes,
   pt.cpu_cost,
   pt.io_cost,
   pt.temp_space,
   pt.access_predicates,
   pt.filter_predicates,
   pt.qblock_name as "Query Block name"
FROM (select *
             from v$sql_plan
             where   sql_id =  '7h35uxf5uhmm1'
             and child_number = 0
            ) pt
CONNECT BY PRIOR pt.id = pt.parent_id
START WITH pt.id = 0;



Получить план из AWR по sql_id и plan_hash_value:

SELECT lpad(' ', 2 * level) || pt.operation || ' ' || pt.options || ' ' ||
       pt.object_name "Query Plan",
       pt.cost,
       pt.cardinality,
       pt.bytes,
       pt.cpu_cost,
       pt.io_cost,
       pt.temp_space,
       pt.access_predicates,
       pt.filter_predicates,
       pt.qblock_name
 FROM (select *
              from dba_hist_sql_plan
              where sql_id = '7h35uxf5uhmm1'
              and plan_hash_value = 1388734953
        ) pt
 CONNECT BY PRIOR pt.id = pt.parent_id
START WITH pt.id = 0;



Для получения плана запроса удобно использовать пакет DBMS_XPLAN

Следующие функции этого пакета :

DBMS_XPLAN.DISPLAY_CURSOR(
   sql_id            IN  VARCHAR2  DEFAULT  NULL,
   cursor_child_no   IN  NUMBER    DEFAULT  0,
   format            IN  VARCHAR2  DEFAULT  'TYPICAL');


DBMS_XPLAN.DISPLAY_AWR(
   sql_id            IN      VARCHAR2,
   plan_hash_value   IN      NUMBER DEFAULT NULL,
   db_id             IN      NUMBER DEFAULT NULL,
   format            IN      VARCHAR2 DEFAULT TYPICAL);


DBMS_XPLAN.DISPLAY_SQLSET(
   sqlset_name      IN  VARCHAR2,
   sql_id           IN  VARCHAR2,
   plan_hash_value  IN NUMBER := NULL,
   format           IN  VARCHAR2  := 'TYPICAL',
   sqlset_owner     IN  VARCHAR2  := NULL)
  RETURN DBMS_XPLAN_TYPE_TABLE PIPELINED;


DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE (
   sql_handle      IN VARCHAR2 := NULL,
   plan_name       IN VARCHAR2 := NULL,
   format          IN VARCHAR2 := 'TYPICAL')
  RETURN DBMS_XPLAN_TYPE_TABLE PIPELINED;


DBMS_XPLAN.DISPLAY_SQL_PATCH_PLAN(
   name             IN VARCHAR2,
   format           IN VARCHAR2 DEFAULT 'TYPICAL')
  RETURN DBMS_XPLAN_TYPE_TABLE PIPELINED;


DBMS_XPLAN.DISPLAY_SQL_PROFILE_PLAN(
   name             IN VARCHAR2,
   format           IN VARCHAR2 DEFAULT 'TYPICAL')
  RETURN DBMS_XPLAN_TYPE_TABLE PIPELINED;



Параметр format управляет уровнем детализации плана.


basic - отображает минимальную информацию о плане выполнения.

- id операции
- имя операции 
- опции

typical (default) - отображает  самую актуальную информацию о плане выполнения.

Тоже что и basic плюс

- #rows
- #bytes
- cost

Также отображается информация

- parallel
- predicate

Исключается тоько информация

- projection
- alias
- remote sql


serial - отображает тоже что и typical

Но не отображает в плане

- parallel

даже если запрос выполняется параллельно.


all - максимальный уровень

Тоже что и typical плюс

- projection
- alias
- remote sql


advanced - отображает тоже что и all

Плюс информацию об используемых Outline (наборы подсказок)
из поля other_xml представления v$sql_plan_statistics_all


adaptive - отображает всё

плюс все потенциальные варианты адаптивного плана выполнения курсора



Примеры:

format => 'basic'

format => 'ALL +peek_binds -alias -predicate'
(т.е. можно добавлять или удалять выводимую информацию)

Например к уровню basic можно добавить вывод дополнительных столбцов столбцов:

format => 'basic +rows +bytes +cost +parallel +partition'

Хотя уровнь all всё это и так включает.

basic +rows +bytes +cost +parallel = typical без time
typical +projection +alias +remote = all
all +outline = advanced


Дополнительно можно добавить

+peeked_binds  - выводит дополнительную секцию со значениями связанных переменных,
                 которые оптимизатор учитывает при подготовке плана выполнения.

+report  - для адаптивного плана

+metrics  - для 12с могут быть показаны спискм доступных/используемых SQL Plan Directives


Чтобы дополнительно добавить столбцы со статистикой ввода-вывода и использования памяти нужно добавить

+iostats
+memstats

или просто ALLSTATS


format => 'advanced allstats'


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

format => 'advanced allstats last'


select * from table (dbms_xplan.display_cursor('adcv4sbhvh2rv',0,'ADVANCED ALLSTATS LAST +peeked_binds +report +metrics'));



Значения столбцов статистики плана выполнения


starts - количество выполнений операции

e-rows - ожидаемое количество строк при каждом выполнении операции

e-time - ожидаемое время выполнения

a-rows - наблюдаемое суммарное количество строк за время всех выполнений операций

a-time - наблюдаемое время выполнения


При добавлении дополнительных столбцов со статистикой ввода-вывода и использования памяти (allstats)
появятся следующие поля:

buffers   - consistent gets + current gets

reads     - physikal reads

0Mem      - сколько потребуется памяти для обработки курсора полностью в памяти (v$sql_workarea.estimated_optimal_size)

1Mem      - сколько потребуется памяти для обработки курсора за один проход (v$sql_workarea.estimated_onepass_size)

used-mem  - реальное значение памяти использованной в течении последнего выполнения курсора (v$sql_workarea.last_memory_used)



Для получения столбцов со статистикой ввода-вывода (allstats) необходимо установить значение параметра statistics_level = ALL.


alter system set statistics_level = all;

или
alter session set statistics_level = all;

наш запрос:
select count(*) from emp;

смотрим план:
select * from table (dbms_xplan.display_cursor('0vx5dc8jftang',1,'ADVANCED ALLSTATS LAST +peeked_binds +report +metrics'));


|Id|Operation|Name|Starts|E-Rows|E-Bytes|Cost (%CPU)|E-Time|A-Rows|A-Time|Buffers|OMem|1Mem|Used-Mem|


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

|Id|Operation|Name|E-Rows|E-Bytes|Cost (%CPU)|E-Time|OMem|1Mem|Used-Mem|


Хинт gather_plan_statistics используется для сбора расширенной статистики выполнения запроса в соответствии с планом выполнения.
Действует аналогично установке значения параметра statistics_level = all или _rowsource_execution_statistics = TRUE на уровне сессии или системы.
Данные по статистике плана выполнения при этом сохраняются в обзоре:
v$sql_plan_statistics_all


set linesize 150
set pagesize 2000
set serveroutput OFF

select /*+ gather_plan_statistics */ count(*) from t;

смотрим план:
select * from table (dbms_xplan.display_cursor('0vx5dc8jftang',1,'ADVANCED ALLSTATS LAST +peeked_binds +report +metrics'));





вторник, 18 сентября 2018 г.

Как восстановить и открыть базу данных


Сценарий 1: доступен Current Controlfile



1) Убедитесь, что Instance is Mounted and ALL Datafiles ONLINE

    Если используется CURRENT CONTROLFILE, вы можете запустить  recover database, и она будет
    применять все архивные файлы и онлайн-текущий редолог, если они доступны, после чего вы можете открыть базу данных.

    Пример:

SQL> select name, controlfile_type from v$database ;

   NAME      CONTROL
   --------- -------
   V1123     CURRENT

   SQL> recover automatic database ;
    ..
   Media recovery complete   
   SQL> alter database open


Сценарий 2: Используем Backup Controlfile



 SQL> select name, controlfile_type from v$database ;

NAME      CONTROL
--------- -------
V1123     BACKUP      


select status,
       resetlogs_change#,
       resetlogs_time,
       checkpoint_change#,
       to_char(checkpoint_time, 'DD-MON-YYYY HH24:MI:SS') as checkpoint_time,
       count(*)
  from v$datafile_header
 group by status, resetlogs_change#, resetlogs_time, checkpoint_change#, checkpoint_time
 order by status, checkpoint_change#, checkpoint_time ;


STATUS  RESETLOGS_CHANGE# RESETLOGS_TIME       CHECKPOINT_CHANGE# CHECKPOINT_TIME        COUNT(*)
------- ----------------- -------------------- ------------------ -------------------- ----------
ONLINE             995548 15-FEB-2012:17:17:20            2446300 13-FEB-2013 15:09:44          1 
ONLINE             995548 15-FEB-2012:17:17:20            2472049 13-FEB-2013 16:02:22          6

Файлы данных имеют разные значения checkpoint_change# (scn), т.е. в несогласованном состоянии.




-- Check for datafile status, and fuzziness
select STATUS, ERROR, FUZZY,  count(*)  from v$datafile_header group by STATUS, ERROR, FUZZY;

STATUS  ERROR                                                      FUZ   COUNT(*)
------- ----------------------------------------------------------------- --- ----------
ONLINE                                                                    YES          7

Существуют файлы в статусе FUZZY




-- Check for MIN, and MAX SCN in Datafiles
select min(CHECKPOINT_CHANGE#), max(CHECKPOINT_CHANGE#) from v$datafile_header;

MIN(CHECKPOINT_CHANGE#) MAX(CHECKPOINT_CHANGE#)
----------------------- -----------------------
                2446300                 2472049


Посмотрим информацию об  online redolog:


select  substr(L.GROUP#,1,6)          GROUP#
       ,substr(L.THREAD#,1,7)         THREAD#
       ,substr(L.SEQUENCE#,1,10)      SEQUENCE#
       ,substr(L.MEMBERS,1,7)         MEMBERS
       ,substr(L.ARCHIVED,1,8)        ARCHIVED
       ,substr(L.STATUS,1,10)         STATUS
       ,substr(L.FIRST_CHANGE#,1,16)  FIRST_CHANGE#
       ,substr(LF.member,1,60)        REDO_LOGFILE
 from GV$LOG L, GV$LOGFILE LF
where L.GROUP# = LF.GROUP# ;

GROUP# THREAD# SEQUENCE#  MEMBERS ARC STATUS     FIRST_CHANGE#    REDO_LOGFILE
------ ------- ---------- ------- --- ---------- ---------------- ------------------------------------------------------------
1      1       454        1       NO  CURRENT    2471963          /u01/app/oracle/oradata/V1123/redo01.log  
3      1       453        1       YES INACTIVE   2471714          /u01/app/oracle/oradata/V1123/redo03.log
2      1       452        1       YES INACTIVE   2451698          /u01/app/oracle/oradata/V1123/redo02.log


Мы видим, что текущий Current Redolog SEQ# 454 доступен.
Найдём начальный first SEQ# 'number' и archivelog file, необходимый для восстановления.
Вся цепочка файлов от first SEQ# 'number' до Current Redolog SEQ# 454 должна быть доступна для восстановления.


Чтобы найти first SEQ# 'number' используем ранее полученный MIN(CHECKPOINT_CHANGE#) 2446300 :

select thread#, sequence#, substr(name,1,80) from v$Archived_log
 where 2446300 between first_change# and next_change#;

   THREAD#  SEQUENCE# SUBSTR(NAME,1,80)
---------- ---------- --------------------------------------------------------------------------------
         1        449 /u01/app/oracle/oradata/V1123/arch1/arch_1_449_775329440.arc
         1        449 /u01/app/oracle/fra/V1123/archivelog/2013_02_13/o1_mf_1_449_8kq7oc6y_.arc
         1        450 /u01/app/oracle/oradata/V1123/arch1/arch_1_450_775329440.arc
         1        450 /u01/app/oracle/fra/V1123/archivelog/2013_02_13/o1_mf_1_450_8kqbn929_.arc


Т.е. для восстановления должны быть доступны все archivelogs начиная с /u01/app/oracle/oradata/V1123/arch1/arch_1_449_775329440.arc  SEQ# 449


select * from v$recover_file;     -- Checking for Datafile(s) which needs recovery

FILE# ONLINE  ONLINE_ ERROR                                                    CHANGE# TIME
----- ------- ------- ----------------------------------------------------------------- ---------- --------------------
    6 ONLINE  ONLINE                                                                       2446300 13-FEB-2013:15:09:44


Как видим data file 6 нуждается в восстановлении.



Если вы используете «BACKUP CONTROLFILE» или ранее использовали команду восстановления с UNTIL CANCEL
то вам нужно восстановиться и «вручную» применить online current redolog..

SQL> select name, controlfile_type from v$database;

NAME      CONTROL
--------- -------
V1123     BACKUP


Запускаем восстановление:

RECOVER DATABASE USING BACKUP CONTROLFILE UNTIL CANCEL;

ORA-00279: change 2446300 generated at 02/13/2013 15:09:44 needed for thread 1
ORA-00289: suggestion : /u01/app/oracle/fra/V1123/archivelog/2013_02_13/o1_mf_1_450_8kqbn929_.arc
ORA-00280: change 2446300 for thread 1 is in sequence #450

Specify log: {=suggested | filename | AUTO | CANCEL}
auto
ORA-00279: change 2451694 generated at 02/13/2013 16:00:25 needed for thread 1
ORA-00289: suggestion : /u01/app/oracle/fra/V1123/archivelog/2013_02_13/o1_mf_1_451_8kqbnbmh_.arc
ORA-00280: change 2451694 for thread 1 is in sequence #451
ORA-00278: log file '/u01/app/oracle/fra/V1123/archivelog/2013_02_13/o1_mf_1_450_8kqbn929_.arc' no longer needed for this recovery
...
 < all required logs applied >
...

ORA-00279: change 2471963 generated at 02/13/2013 16:02:19 needed for thread 1
ORA-00289: suggestion : /u01/app/oracle/fra/V1123/archivelog/2013_02_13/o1_mf_1_454_%u_.arc
ORA-00280: change 2471963 for thread 1 is in sequence #454
ORA-00278: log file '/u01/app/oracle/fra/V1123/archivelog/2013_02_13/o1_mf_1_453_8kqbqvrk_.arc' no longer needed for this recovery   < - All Redo, up to and including SEQ# 453 is applied


ORA-00308: cannot open archived log '/u01/app/oracle/fra/V1123/archivelog/2013_02_13/o1_mf_1_454_%u_.arc'    < - "SEQ# 454" requested, which is in ONLINE REDOLOG as seen before
ORA-27037: unable to obtain file status
Linux-x86_64 Error: 2: No such file or directory
Additional information: 3


ORA-01547: warning: RECOVER succeeded but OPEN RESETLOGS would get error below
ORA-01194: file 1 needs more recovery to be consistent
ORA-01110: data file 1: '/u01/app/oracle/oradata/V1123/system01.dbf'


Все archivelogs, включая SEQ# 453 были применены.
Процесс восстановления запрашивает следующий "SEQ# 454", который содержится в ONLINE REDOLOG.


select * from v$recover_file;

FILE# ONLINE  ONLINE_ ERROR   CHANGE# TIME
----- ------- ------- ------  ------- --------------------
    6 ONLINE  ONLINE          2471963 13-FEB-2013:16:02:19


Как видим data file 6 попрежнему нуждается в восстановлении.


Пробуем открыть:

alter database open resetlogs;
alter database open resetlogs
*
ERROR at line 1:
ORA-01194: file 1 needs more recovery to be consistent
ORA-01110: data file 1: '/u01/app/oracle/oradata/V1123/system01.dbf'

Не получается.


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

select  min(FHSCN) "LOW FILEHDR SCN"
      , max(FHSCN) "MAX FILEHDR SCN"
      , max(FHAFS) "Min PITR ABSSCN"
  from X$KCVFH;

LOW FILEHDR SCN  MAX FILEHDR SCN  Min PITR ABSSCN
---------------- ---------------- ----------------
2446300          2472049          0


LOW FILEHDR SCN - SCN с которого начинается recovery process
MAX FILEHDR SCN - SCN до которого необходимо восстановиться чтобы все файлы данных были согласованы.

Если  "Min PITR ABSSCN"  != 0 AND  >  "MAX FILEHDR SCN"
то "Min PITR ABSSCN" - это SCN, до которого необходимо восстановиться чтобы обеспечить согласованность всех файлов данных.

ABSSCN = Absolute SCN


В приведенном выше примере  мы использовали redo (archivelogs), для восстановления файла данных 6, но данный файл все еще требует дополнительного восстановления.
Восстановление базы данных не завершилось, потому что текущий online 'current' redolog не применяется автоматически с 'BACKUP' controlfile.

Поскольку мы используем Backup Controlfile, мы должны «вручную» применять online 'current' redolog  /u01/app/oracle/oradata/V1123/redo01.log,
имеющий SEQ#454 (SCN 2472049)!


Поскольку мы восстанавливаемся с помощью Backup Controlfile или
Controlfile созданного из Tracefile (sql> alter database backup to trace;),
то запрос v$log/v$logfile, не даст правильной информации, какой logfile содержит необходимый номер последовательности (seq#).

Чтобы найти  Online log, который будет использоваться для восстановления:

   a: Проверьте файл Alert.log на последние sequences, используемые с 'Online Redolog files'

   b: Если Alert.log потерян, вы можете просто попробовать все онлайн-файлы redolog, если выбран неправильный файл журнала, ничего не будет применено,
      но вы увидите в выходном сообщении, какая последовательность находится в этом онлайн-файле redolog.
      Затем просто попробуйте следующий онлайн-файл redolog, пока не получите сообщение «media recovery complete».

   c: Вы также можете создать dump the file log file headers for Online redolog file(s).
      Пример:
      --------
      sql> alter system dump logfile '/u01/app/oracle/oradata/V1123/redo01.log' scn min 1 scn max 1;

      - Получим файл трассировки с дампом заголовка в папку «trace» (11g) [или udump (<= 10g)]
      - Найдите в файле трассировки аналогичные записи, например ...
      ~~~
      ..
       descrip: "Thread 0001, Seq # 0000000454 ...
       ..
       Low scn: 0x .....
       Next scn: 0x .....
      ..
      ~~~


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

RECOVER DATABASE USING BACKUP CONTROLFILE UNTIL CANCEL;
.
ORA-00279: change 2471963 generated at 02/13/2013 16:02:19 needed for thread 1
ORA-00289: suggestion : /u01/app/oracle/fra/V1123/archivelog/2013_02_13/o1_mf_1_454_%u_.arc
ORA-00280: change 2471963 for thread 1 is in sequence #454


Specify log: {=suggested | filename | AUTO | CANCEL}
'/u01/app/oracle/oradata/V1123/redo01.log'                  < - specify the online redologfile having SEQ# 454 to be manually applied
Log applied.
Media recovery complete.

SQL> alter database open resetlogs;

Database altered.


Если после применения всех archive logs и online redologfile база данных не открывается
пожалуйста, предоставьте следующий вывод сценария в поддержку Oracle, чтобы помочь в восстановлении.
(Загрузите файл: recovery_info.txt)


set pagesize 20000
     set linesize 180
     set pause off
     set serveroutput on
     set feedback on
     set echo on
     set numformat 999999999999999

     Spool recovery_info.txt
     select substr(name, 1, 50), status from v$datafile;
     select substr(name,1,40), recover, fuzzy, checkpoint_change# from v$datafile_header;
     select GROUP#,substr(member,1,60) from v$logfile;
     select * from v$recover_file;
     select distinct status from v$backup;
     select hxfil FILENUMBER, fhsta STATUS, fhscn SCN, FHAFS ABSSCN , fhrba_Seq SEQUENCE from x$kcvfh;
     select distinct (fuzzy) from v$datafile_header;
     spool off
     exit;







вторник, 7 августа 2018 г.

SQLcl sqlformat


DEFAULT

Формат DEFAULT очищает все предыдущие настройки SQLFORMAT и возвращает значение по умолчанию.

SET SQLFORMAT DEFAULT
select name, created, log_mode, archive_change# from v$database;

SQL Format Cleared

NAME      CREATED   LOG_MODE     ARCHIVE_CHANGE#
--------- --------- ------------ ---------------
MYDB      02-AUG-18 ARCHIVELOG           1219143


CSV

Формат CSV создает стандартный вывод с разделителями-запятыми, с строковыми значениями,
заключенными в двойные кавычки. Первая строка содержит имена столбцов.

SET SQLFORMAT CSV
select name, created, log_mode, archive_change# from v$database;


"NAME","CREATED","LOG_MODE","ARCHIVE_CHANGE#"
"MYDB",02-AUG-18,"ARCHIVELOG",1219143


HTML

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

SET SQLFORMAT HTML
select name, created, log_mode, archive_change# from v$database;


<!DOCTYPE html> <html> <head> <meta charset='UTF-8'> <title>Responsive Table</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> * { margin: 0; padding: 0; } body { font: 14px/1.4 Georgia, Serif; } /* Generic Styling, for Desktops/Laptops */ table { width: 100%; border-collapse: collapse; } /* Zebra striping */ tr:nth-of-type(odd) { background: #eee; } th { background: #333; color: white; font-weight: bold; } td, th { padding: 6px; border: 1px solid #9B9B9B; text-align: left; } @media only screen and (max-width: 760px), (min-device-width: 768px) and (max-device-width: 1024px) { table, thead, tbody, th, td, tr { display: block; } thead tr { position: absolute;top: -9999px;left: -9999px;} tr { border: 1px solid #9B9B9B; } td { border: none;border-bottom: 1px solid #9B9B9B; position: relative;padding-left: 50%; } td:before { position: absolute;top: 6px;left: 6px;width: 45%; padding-right: 10px; white-space: nowrap;} /* Label the data */ td:nth-of-type(0):before { content: "NAME"; } td:nth-of-type(1):before { content: "CREATED"; } td:nth-of-type(2):before { content: "LOG_MODE"; } td:nth-of-type(3):before { content: "ARCHIVE_CHANGE#"; } } /* Smartphones (portrait and landscape) ----------- */ @media only screen and (min-device-width : 320px) and (max-device-width : 480px) { body { padding: 0; margin: 0; width: 320px; } } /* iPads (portrait and landscape) ----------- */ @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) { body { width: 495px; } } </style> <!--<![endif]--> <script type="text/javascript"> lsearch = function(){ //this.term = document.getElementById('S').value.toUpperCase(); var s = document.getElementById('search').value.toLowerCase(); rows = document.getElementById('data').getElementsByTagName('TR'); for(var i=0;i<rows.length;i++){ if (s =="" ){ rows[i].style.display =''; } else if ( rows[i].innerText.toLowerCase().indexOf(s) != -1 ) { rows[i].style.display =''; } else { rows[i].style.display ='none'; } } this.time = false; } </script> </head> <body> <div><input type="text" size="30" maxlength="1000" value="" id="search" onkeyup="lsearch();" /><input type="button" value="Go" onclick="lsearch();"/> </div> <table><thead><tr> <th>NAME</th> <th>CREATED</th> <th>LOG_MODE</th> <th>ARCHIVE_CHANGE#</th> </tr></thead> <tbody id="data"> <tr> <td>MYDB</td> <td>02-AUG-18</td> <td>ARCHIVELOG</td> <td align="right">1219143</td> </tr> </tbody></table><!-- SQL: null--></body></html>


XML

Формат XML создает XML-документ на основе тегов. Все данные представлены как теги CDATA.

SET SQLFORMAT XML
select name, created, log_mode, archive_change# from v$database;



<?xml version='1.0' encoding='UTF-8' ?> <RESULTS> <ROW> <COLUMN NAME="NAME"><![CDATA[MYDB]]></COLUMN> <COLUMN NAME="CREATED"><![CDATA[02-AUG-18]]></COLUMN> <COLUMN NAME="LOG_MODE"><![CDATA[ARCHIVELOG]]></COLUMN> <COLUMN NAME="ARCHIVE_CHANGE#"><![CDATA[1219143]]></COLUMN> </ROW> </RESULTS>

JSON

Формат JSON создает документ JSON, содержащий определения столбцов вместе с данными,
которые они содержат.

SET SQLFORMAT JSON
select name, created, log_mode, archive_change# from v$database;



 <?xml version='1.0' encoding='UTF-8' ?> <RESULTS> <ROW> <COLUMN NAME="NAME"><![CDATA[MYDB]]></COLUMN> <COLUMN NAME="CREATED"><![CDATA[02-AUG-18]]></COLUMN> <COLUMN NAME="LOG_MODE"><![CDATA[ARCHIVELOG]]></COLUMN> <COLUMN NAME="ARCHIVE_CHANGE#"><![CDATA[1219143]]></COLUMN> </ROW> </RESULTS> {"results":[{"columns":[{"name":"NAME","type":"VARCHAR2"},{"name":"CREATED","type":"DATE"},{"name":"LOG_MODE","type":"VARCHAR2"},{"name":"ARCHIVE_CHANGE#","type":"NUMBER"}],"items": [ {"name":"MYDB","created":"02-AUG-18","log_mode":"ARCHIVELOG","archive_change#":1219143} ]}]}


ANSICONSOLE

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

SET SQLFORMAT ANSICONSOLE
select name, created, log_mode, archive_change# from v$database;


NAME   CREATED     LOG_MODE     ARCHIVE_CHANGE#  
MYDB   02-AUG-18   ARCHIVELOG           1219143


INSERT

Формат INSERT создает инструкции INSERT, которые могут использоваться для воссоздания строк в таблице.

SET SQLFORMAT INSERT
select name, created, log_mode, archive_change# from v$database;

REM INSERTING into V$DATABASE
SET DEFINE OFF;
Insert into V$DATABASE (NAME,CREATED,LOG_MODE,ARCHIVE_CHANGE#) values ('MYDB',to_date('02-AUG-18','DD-MON-RR'),'ARCHIVELOG',1219143);


LOADER

Формат LOADER создает выходные данные разделённые символом "|" с строковыми значениями,
заключенными в двойные кавычки. Имена столбцов не включаются в вывод.

SET SQLFORMAT LOADER
select name, created, log_mode, archive_change# from v$database;


"MYDB"|2018-08-02 16:40:51|"ARCHIVELOG"|1219143|


FIXED

Формат FIXED создает столбцы фиксированной ширины со всеми данными, заключенными в двойные кавычки.
Первая строка содержит имена столбцов.

SET SQLFORMAT FIXED
select name, created, log_mode, archive_change# from v$database;

"NAME"                        "CREATED"                     "LOG_MODE"                    "ARCHIVE_CHANGE#"            
"MYDB"                        "02-AUG-18"                   "ARCHIVELOG"                  "1219143"                    


DELIMITED

Формат DELIMITED - это особый случай, который позволяет вам вручную определить строку разделителя,
а также символы, которые будут использоваться для обрамления строковых значений.
Основной формат выглядит следующим образом.
SET SQLFORMAT DELIMITED <разделитель> <слева от строки> <справа от строки>

SET SQLFORMAT DELIMITED @#@ " "
select name, created, log_mode, archive_change# from v$database;


"NAME"@#@"CREATED"@#@"LOG_MODE"@#@"ARCHIVE_CHANGE#"
"MYDB"@#@02-AUG-18@#@"ARCHIVELOG"@#@1219143

SET SQLFORMAT DELIMITED ; ' '
select name, created, log_mode, archive_change# from v$database;


'NAME';'CREATED';'LOG_MODE';'ARCHIVE_CHANGE#'
'MYDB';02-AUG-18;'ARCHIVELOG';1219143

SET SQLFORMAT DELIMITED ;
select name, created, log_mode, archive_change# from v$database;

"NAME","CREATED","LOG_MODE","ARCHIVE_CHANGE#"
"MYDB",02-AUG-18,"ARCHIVELOG",1219143

SET SQLFORMAT DELIMITED ; # $
select name, created, log_mode, archive_change# from v$database;

#NAME$;#CREATED$;#LOG_MODE$;#ARCHIVE_CHANGE#$
#MYDB$;02-AUG-18;#ARCHIVELOG$;1219143

по умолчанию разделитель запятая а строка заключается в двойные кавычки:


SET SQLFORMAT DELIMITED
select name, created, log_mode, archive_change# from v$database;


"NAME","CREATED","LOG_MODE","ARCHIVE_CHANGE#"
"MYDB",02-AUG-18,"ARCHIVELOG",1219143




среда, 4 апреля 2018 г.

TFA Collector

 

 TFA Collector - инструмент для расширенного сбора диагностических данных (Doc ID 1513912.1 )


Root / Daemon Install:
 
1. Download from 1513912.1
2. Copy to one required machine and unzip
3. Run ./installTFA< platform > 
 
 

 Деинсталлируем TFA Collector, который по умолчанию был установлен, при инсталляции Grid Infrastructure.

 
На каждой из нод (пример нля ноды 2)запускаем: 
 
[root@rac12c02 ~]# export GRID_HOME=/u01/app/grid/product/12.2.0.1
[root@rac12c02 ~]# $GRID_HOME/bin/tfactl  uninstall
 
TFA will be uninstalled on node rac12c02 : 

Removing TFA from rac12c02...

Stopping TFA Support Tools...

Stopping TFA in rac12c02...

Shutting down TFA
Removed symlink /etc/systemd/system/multi-user.target.wants/oracle-tfa.service.
Removed symlink /etc/systemd/system/graphical.target.wants/oracle-tfa.service.
. . . . . 
. . . 
Successfully shutdown TFA..

Deleting TFA support files on rac12c02:
Removing /u01/app/oracle/tfa/rac12c02/database...
Removing /u01/app/oracle/tfa/rac12c02/log...
Removing /u01/app/oracle/tfa/rac12c02/output...
Removing /u01/app/oracle/tfa/rac12c02...
Removing /u01/app/oracle/tfa...
Removing /etc/rc.d/rc0.d/K17init.tfa
Removing /etc/rc.d/rc1.d/K17init.tfa
Removing /etc/rc.d/rc2.d/K17init.tfa
Removing /etc/rc.d/rc4.d/K17init.tfa
Removing /etc/rc.d/rc6.d/K17init.tfa
Removing /etc/init.d/init.tfa...
Removing /u01/app/grid/product/12.2.0.1/bin/tfactl...
Removing /u01/app/grid/product/12.2.0.1/tfa/bin...
Removing /u01/app/grid/product/12.2.0.1/tfa/rac12c02...
Removing /u01/app/grid/product/12.2.0.1/tfa...

[root@rac12c02 ~]# 
 
 

Устанавливаем новый TFA Collector:

(Установка с одной ноды)
 
 
[root@rac12c01 ~]# cd /home/oracle/Downloads/

[root@rac12c01 ~]# unzip TFA-LINUX_v18.1.1.zip

[root@rac12c01 Downloads]# ls -l
total 351592
-rwxr-xr-x 1 root   root     180549652 Feb  1 13:11 installTFA-LINUX
-rw-r--r-- 1 oracle oinstall 179401036 Apr  4 17:59 TFA-LINUX_v18.1.1.zip

[root@rac12c01 Downloads]# ./installTFA-LINUX
 
TFA Installation Log will be written to File : /tmp/tfa_install_15962_2018_04_04-18_37_37.log

Starting TFA installation

TFA Version: 181100 Build Date: 201802010159

Enter a location for installing TFA (/tfa will be appended if not supplied) [/home/oracle/Downloads/tfa]:
/u01/app/oracle/tfa

Running Auto Setup for TFA as user root...

Would you like to do a [L]ocal only or [C]lusterwide installation ? [L|l|C|c] [C] : C

The following installation requires temporary use of SSH.
If SSH is not configured already then we will remove SSH 
when complete.
  Do you wish to Continue ? [Y|y|N|n] [Y] Y
Installing TFA now...

Discovering Nodes and Oracle resources

Starting Discovery...


Getting list of nodes in cluster . . . . .

List of nodes in cluster:
rac12c01
rac12c02


Checking ssh user equivalency settings on all nodes in cluster

Node rac12c02 is not configured for ssh user equivalency and  the script uses ssh to install TFA on remote nodes.

Without this facility the script cannot install TFA on the remote nodes. 

Do you want to configure SSH for user root on rac12c02 [y/n] y
Generating keys on rac12c01...

Copying keys to rac12c02...

/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@rac12c02's password: 

CRS_HOME=/u01/app/grid/product/12.2.0.1

Searching for running databases...
1. TESTDB_OMEGA


Searching out ORACLE_HOME for selected databases...


Getting Oracle Inventory...

ORACLE INVENTORY: /u01/app/oraInventory


Discovery Complete...



TFA Will be Installed on the Following Nodes:
++++++++++++++++++++++++++++++++++++++++++++

Install Nodes
=============
rac12c01
rac12c02

Do you wish to make changes to the Node List ? [Y/y/N/n] [N] N

TFA will scan the following Directories
++++++++++++++++++++++++++++++++++++++++++++

.-------------------------------------------------------------------------.
|                                 rac12c01                                |
+--------------------------------------------------------------+----------+
| Trace Directory                                              | Resource |
+--------------------------------------------------------------+----------+
| /u01/app/grid/product/12.2.0.1/cfgtoollogs                   | CFGTOOLS |
| /u01/app/grid/product/12.2.0.1/crf/db/rac12c01               | CRS      |
| /u01/app/grid/product/12.2.0.1/crs/log                       | CRS      |
| /u01/app/grid/product/12.2.0.1/css/log                       | CRS      |
| /u01/app/grid/product/12.2.0.1/cv/log                        | CRS      |
| /u01/app/grid/product/12.2.0.1/evm/admin/log                 | CRS      |
| /u01/app/grid/product/12.2.0.1/evm/admin/logger              | CRS      |
| /u01/app/grid/product/12.2.0.1/evm/log                       | CRS      |
| /u01/app/grid/product/12.2.0.1/install                       | INSTALL  |
| /u01/app/grid/product/12.2.0.1/inventory/ContentsXML         | INSTALL  |
| /u01/app/grid/product/12.2.0.1/log                           | CRS      |
| /u01/app/grid/product/12.2.0.1/network/log                   | CRS      |
| /u01/app/grid/product/12.2.0.1/opmn/logs                     | CRS      |
| /u01/app/grid/product/12.2.0.1/racg/log                      | CRS      |
| /u01/app/grid/product/12.2.0.1/rdbms/log                     | ASM      |
| /u01/app/grid/product/12.2.0.1/scheduler/log                 | CRS      |
| /u01/app/grid/product/12.2.0.1/srvm/log                      | CRS      |
| /u01/app/oraInventory/ContentsXML                            | INSTALL  |
| /u01/app/oraInventory/logs                                   | INSTALL  |
| /u01/app/oracle/cfgtoollogs                                  | CFGTOOLS |
| /u01/app/oracle/crsdata/rac12c01/acfs                        | ACFS     |
| /u01/app/oracle/crsdata/rac12c01/afd                         | ASM      |
| /u01/app/oracle/crsdata/rac12c01/chad                        | CRS      |
| /u01/app/oracle/crsdata/rac12c01/core                        | CRS      |
| /u01/app/oracle/crsdata/rac12c01/crsconfig                   | CRS      |
| /u01/app/oracle/crsdata/rac12c01/crsdiag                     | CRS      |
| /u01/app/oracle/crsdata/rac12c01/cvu                         | CRS      |
| /u01/app/oracle/crsdata/rac12c01/evm                         | CRS      |
| /u01/app/oracle/crsdata/rac12c01/output                      | CRS      |
| /u01/app/oracle/crsdata/rac12c01/trace                       | CRS      |
| /u01/app/oracle/diag/asm/+asm/+ASM1/cdump                    | ASM      |
| /u01/app/oracle/diag/asmtool/user_oracle/host_2836368897_107 | ASMTOOL  |
| /u01/app/oracle/diag/asmtool/user_oracle/host_2836368897_107 | ASMTOOL  |
| /u01/app/oracle/diag/asmtool/user_root/host_2836368897_107/c | ASMTOOL  |
| /u01/app/oracle/diag/asmtool/user_root/host_2836368897_107/t | ASMTOOL  |
| /u01/app/oracle/diag/clients/user_oracle/host_2836368897_107 | DBCLIENT |
| /u01/app/oracle/diag/clients/user_oracle/host_2836368897_107 | DBCLIENT |
| /u01/app/oracle/diag/crs/rac12c01/crs/cdump                  | CRS      |
| /u01/app/oracle/diag/crs/rac12c01/crs/trace                  | CRS      |
| /u01/app/oracle/diag/rdbms/_mgmtdb/-MGMTDB/cdump             | RDBMS    |
| /u01/app/oracle/diag/rdbms/_mgmtdb/-MGMTDB/trace             | RDBMS    |
| /u01/app/oracle/diag/rdbms/testdb_omega/TESTDB1/cdump        | RDBMS    |
| /u01/app/oracle/diag/rdbms/testdb_omega/TESTDB1/trace        | RDBMS    |
| /u01/app/oracle/diag/tnslsnr                                 | TNS      |
| /u01/app/oracle/diag/tnslsnr/rac12c01/listener/cdump         | TNS      |
| /u01/app/oracle/diag/tnslsnr/rac12c01/listener/trace         | TNS      |
| /u01/app/oracle/diag/tnslsnr/rac12c01/listener_scan1/cdump   | TNS      |
| /u01/app/oracle/diag/tnslsnr/rac12c01/listener_scan1/trace   | TNS      |
| /u01/app/oracle/product/12.2.0.1/cfgtoollogs                 | CFGTOOLS |
| /u01/app/oracle/product/12.2.0.1/install                     | INSTALL  |
| /u01/app/oracle/product/12.2.0.1/rdbms/log                   | RDBMS    |
'--------------------------------------------------------------+----------'


Installing TFA on rac12c01:
HOST: rac12c01 TFA_HOME: /u01/app/oracle/tfa/rac12c01/tfa_home

Installing TFA on rac12c02:
HOST: rac12c02 TFA_HOME: /u01/app/oracle/tfa/rac12c02/tfa_home

.-----------------------------------------------------------------------------.
| Host     | Status of TFA | PID   | Port | Version    | Build ID             |
+----------+---------------+-------+------+------------+----------------------+
| rac12c01 | RUNNING       | 16738 | 5000 | 18.1.1.0.0 | 18110020180201015951 |
| rac12c02 | RUNNING       |   717 | 5000 | 18.1.1.0.0 | 18110020180201015951 |
'----------+---------------+-------+------+------------+----------------------'


Running Inventory in All Nodes...

Enabling Access for Non-root Users on rac12c01...

Adding default users to TFA Access list...

Summary of TFA Installation:
.-------------------------------------------------------------.
|                           rac12c01                          |
+---------------------+---------------------------------------+
| Parameter           | Value                                 |
+---------------------+---------------------------------------+
| Install location    | /u01/app/oracle/tfa/rac12c01/tfa_home |
| Repository location | /u01/app/oracle/tfa/repository        |
| Repository usage    | 0 MB out of 6683 MB                   |
'---------------------+---------------------------------------'

.-------------------------------------------------------------.
|                           rac12c02                          |
+---------------------+---------------------------------------+
| Parameter           | Value                                 |
+---------------------+---------------------------------------+
| Install location    | /u01/app/oracle/tfa/rac12c02/tfa_home |
| Repository location | /u01/app/oracle/tfa/repository        |
| Repository usage    | 0 MB out of 6683 MB                   |
'---------------------+---------------------------------------'

TFA is successfully installed...

Usage : /u01/app/grid/product/12.2.0.1/bin/tfactl  [options]
    commands:diagcollect|collection|analyze|ips|run|start|stop|enable|disable|status|print|access|purge|directory|host|receiver|set|toolstatus|uninstall|diagnosetfa|syncnodes|setupmos|upload
For detailed help on each command use:
  /u01/app/grid/product/12.2.0.1/bin/tfactl  -help


Moving Install log file to /u01/app/oracle/tfa/rac12c01/tfa_home/log
 
[root@rac12c01 Downloads]# 
 
  

Настройка SUDO для запуска утилиты tfactl с правами Рута для учётной записи oracle  

 
На каждой ноде:
 
$ su – root

# vi /etc/sudoers


oracle  ALL=NOPASSWD:/u01/app/oracle/tfa/bin/tfactl
 
 
Проверяем: 
 
[oracle@rac12c01 ~]$ sudo /u01/app/oracle/tfa/bin/tfactl -h
 
  

Настройка автозапуска:

 
[oracle@rac12c01 ~]$ sudo /u01/app/oracle/tfa/bin/tfactl status

.------------------------------------------------------------------------------------------------.
| Host     | Status of TFA | PID   | Port | Version    | Build ID             | Inventory Status |
+----------+---------------+-------+------+------------+----------------------+------------------+
| rac12c02 | RUNNING       |   717 | 5000 | 18.1.1.0.0 | 18110020180201015951 | RUNNING          |
| rac12c01 | RUNNING       | 16738 | 5000 | 18.1.1.0.0 | 18110020180201015951 | RUNNING          |
'----------+---------------+-------+------+------------+----------------------+------------------'
 
Разрешить auto-start для TFA Collector на каждой ноде: 
 
[oracle@rac12c01 ~]$ sudo /u01/app/oracle/tfa/bin/tfactl enable
[oracle@rac12c02 ~]$ sudo /u01/app/oracle/tfa/bin/tfactl enable
 
 
Проверка:

[oracle@rac12c01 ~]$ sudo /u01/app/oracle/tfa/bin/tfactl status

.------------------------------------------------------------------------------------------------.
| Host     | Status of TFA | PID   | Port | Version    | Build ID             | Inventory Status |
+----------+---------------+-------+------+------------+----------------------+------------------+
| rac12c02 | RUNNING       |   717 | 5000 | 18.1.1.0.0 | 18110020180201015951 | COMPLETE         |
| rac12c01 | RUNNING       | 16738 | 5000 | 18.1.1.0.0 | 18110020180201015951 | COMPLETE         |
'----------+---------------+-------+------+------------+----------------------+------------------' 
 
[oracle@rac12c01 ~]$ 

 
 
 

 
 
 
 

четверг, 22 марта 2018 г.

Create VM (VirtualBox)

VirtualBox установлен:

C:\Program Files\Oracle\VirtualBox\VirtualBox.exe
C:\Users\angor\VirtualBox VMs


Дистрибутив OEL и VBoxGuestAdditions

C:\distrib\oel\V921569-01.iso
C:\distrib\oel\VBoxGuestAdditions_5.2.6.iso


cd C:\Program Files\Oracle\VirtualBox\


1. Создание VM на Windows Host Operating System


-- Создаём новый 50G виртуальный hard disk image с именем 12cRAC1.vdi:
VBoxManage createhd --filename "C:\Users\angor\VirtualBox VMs\12cRAC1.vdi" --size 51200 --format VDI --variant Fixed

-- Создаём новую Virtual Machine с именем 12cRAC1:
VBoxManage createvm --name 12cRAC1 --ostype "Oracle_64" --register

-- Добавим SATA controller:
VBoxManage storagectl 12cRAC1 --name "SATA" --add sata --controller IntelAHCI

-- Подключим виртуальный диск:
VBoxManage storageattach 12cRAC1 --storagectl "SATA" --port 0 --device 0 --type hdd --medium "C:\Users\angor\VirtualBox VMs\12cRAC1.vdi"

-- Добавим IDE controller:
VBoxManage storagectl 12cRAC1 --name "IDE" --add ide

-- Подключим DVD drive с ISO файлом дистрибутива Oracle Linux 7.3:
VBoxManage storageattach 12cRAC1 --storagectl "IDE" --port 0 --device 0 --type dvddrive --medium C:\distrib\oel\V921569-01.iso

-- Подключим DVD drive с ISO файлом дистрибутива VBoxGuestAdditions:
VBoxManage storageattach 12cRAC1 --storagectl "IDE" --port 1 --device 0 --type dvddrive --medium C:\distrib\oel\VBoxGuestAdditions_5.2.8.iso

-- Системные настройки:
VBoxManage modifyvm 12cRAC1 --ioapic on
VBoxManage modifyvm 12cRAC1 --boot1 dvd --boot2 disk --boot3 none --boot4 none
VBoxManage modifyvm 12cRAC1 --cpus 2 --memory 4096 --vram 128
VBoxManage hostonlyif create
VBoxManage modifyvm 12cRAC1 --nic1 nat --nic2 hostonly --nic3 intnet


2. Установка  Oracle Linux 7.3:


Server with GUI

Выбираем следующее:

Hardware Monitoring Utilities
Java Platform
KDE
Large Systems Performance
Network file system client
Performance Tools
Compatibility Libraries
Development Tools


Сетевые настройки такие:

hostname: rac12c01
enp0s3 (eth0): DHCP (Connect Automatically)

enp0s8 (eth1): IP= 192.168.10.11,
               Subnet=255.255.255.0,
               Gateway=192.168.10.1,
               DNS=192.168.10.1,
               Search=localdomain (Connect Automatically)

enp0s9 (eth2): IP= 192.168.20.11,
               Subnet=255.255.255.0,
               Gateway=(blank),
               DNS=(blank),
               Search=(blank) (Connect Automatically)



Сеть можно будет настроить позже с помощью  NetworkManager:


Для rac12c01:

root@rac12c01# nmcli con del enp0s3
root@rac12c01# nmcli con add con-name enp0s3 ifname enp0s3 type ethernet

root@rac12c01# nmcli con del enp0s8
root@rac12c01# nmcli con add con-name enp0s8 ifname enp0s8 type ethernet ip4 192.168.10.11/24 gw4 192.168.10.1
root@rac12c01# nmcli con mod enp0s8 ipv4.dns 192.168.10.1
root@rac12c01# nmcli con mod enp0s8 ipv4.dns-search localdomain
root@rac12c01# nmcli con mod enp0s8 autoconnect true

root@rac12c01# nmcli con del enp0s9
root@rac12c01# nmcli con add con-name enp0s9 ifname enp0s9 type ethernet ip4 192.168.20.11/24
root@rac12c01# nmcli con mod enp0s9 autoconnect true

root@rac12c01# nmcli con mod enp0s3 ipv6.method "ignore"
root@rac12c01# nmcli con mod enp0s8 ipv6.method "ignore"
root@rac12c01# nmcli con mod enp0s9 ipv6.method "ignore"


Для rac12c02:

root@rac12c02# nmcli con del enp0s3
root@rac12c02# nmcli con add con-name enp0s3 ifname enp0s3 type ethernet

root@rac12c02# nmcli con del enp0s8
root@rac12c02# nmcli con add con-name enp0s8 ifname enp0s8 type ethernet ip4 192.168.10.12/24 gw4 192.168.10.1
root@rac12c02# nmcli con mod enp0s8 ipv4.dns 192.168.10.1
root@rac12c02# nmcli con mod enp0s8 ipv4.dns-search localdomain
root@rac12c02# nmcli con mod enp0s8 autoconnect true

root@rac12c02# nmcli con del enp0s9
root@rac12c02# nmcli con add con-name enp0s9 ifname enp0s9 type ethernet ip4 192.168.20.12/24
root@rac12c02# nmcli con mod enp0s9 autoconnect true

root@rac12c02# nmcli con mod enp0s3 ipv6.method "ignore"
root@rac12c02# nmcli con mod enp0s8 ipv6.method "ignore"
root@rac12c02# nmcli con mod enp0s9 ipv6.method "ignore"


Или так


Для rac12c01:

root@rac12c01# nmcli con del enp0s3
root@rac12c01# nmcli con del enp0s8
root@rac12c01# nmcli con del enp0s9
root@rac12c01# nmcli con add con-name enp0s3 ifname enp0s3 type ethernet
root@rac12c01# nmcli con add con-name enp0s8 ifname enp0s8 type ethernet
root@rac12c01# nmcli con add con-name enp0s9 ifname enp0s9 type ethernet
root@rac12c01# nmcli con mod enp0s8 ipv4.method manual ipv4.address 192.168.10.11/24 ipv4.gateway 192.168.10.1 ipv4.dns 192.168.10.1 ipv4.dns-search localdomain autoconnect true
root@rac12c01# nmcli con mod enp0s9 ipv4.method manual ipv4.address 192.168.20.11/24 autoconnect true


Для rac12c02:

root@rac12c02# nmcli con del enp0s3
root@rac12c02# nmcli con del enp0s8
root@rac12c02# nmcli con del enp0s9
root@rac12c02# nmcli con add con-name enp0s3 ifname enp0s3 type ethernet
root@rac12c02# nmcli con add con-name enp0s8 ifname enp0s8 type ethernet
root@rac12c02# nmcli con add con-name enp0s9 ifname enp0s9 type ethernet
root@rac12c02# nmcli con mod enp0s8 ipv4.method manual ipv4.address 192.168.10.12/24 ipv4.gateway 192.168.10.1 ipv4.dns 192.168.10.1 ipv4.dns-search localdomain autoconnect true
root@rac12c02# nmcli con mod enp0s9 ipv4.method manual ipv4.address 192.168.20.12/24 autoconnect true


# nmcli con reload



[root@rac12c01 ~]# cd /etc/sysconfig/network-scripts/
[root@rac12c01 network-scripts]#

[root@rac12c01 network-scripts]# ls -l |grep ifcfg
-rw-r--r--  1 root root    58 Mar 25  2018 ifcfg-enp0s3
-rw-r--r--. 1 root root   370 Mar  3  2018 ifcfg-enp0s8
-rw-r--r--. 1 root root   312 Mar  3  2018 ifcfg-enp0s9
-rw-r--r--. 1 root root   254 May  3  2017 ifcfg-lo
[root@rac12c01 network-scripts]#

[root@rac12c01 network-scripts]# more ifcfg-enp0s3
BOOTPROTO=dhcp
DEVICE=enp0s3
ONBOOT=yes
NM_CONTROLLED=no
[root@rac12c01 network-scripts]#


[root@rac12c01 network-scripts]# more ifcfg-enp0s8
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=none
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=no
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=enp0s8
UUID=c0fecc6f-b5dc-4118-b96e-f5f6c7e23be1
DEVICE=enp0s8
ONBOOT=yes
IPADDR=192.168.10.11
PREFIX=24
GATEWAY=192.168.10.1
DNS1=192.168.10.1
DOMAIN=localdomain
[root@rac12c01 network-scripts]#


[root@rac12c01 network-scripts]# more ifcfg-enp0s9
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=none
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=no
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=enp0s9
UUID=ad583180-d0fb-4fb9-b8da-40974e4fd937
DEVICE=enp0s9
ONBOOT=yes
IPADDR=192.168.20.11
PREFIX=24
[root@rac12c01 network-scripts]#


[root@rac12c01 network-scripts]# more ifcfg-lo
DEVICE=lo
IPADDR=127.0.0.1
NETMASK=255.0.0.0
NETWORK=127.0.0.0
# If you're having problems with gated making 127.0.0.0/8 a martian,
# you can change this to something else (255.255.255.255, for example)
BROADCAST=127.255.255.255
ONBOOT=yes
NAME=loopback
[root@rac12c01 network-scripts]#




[root@rac12c01 network-scripts]# ifconfig -a
enp0s3: flags=4163  mtu 1500
        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255
        inet6 fe80::a00:27ff:fe73:f560  prefixlen 64  scopeid 0x20
        ether 08:00:27:73:f5:60  txqueuelen 1000  (Ethernet)
        RX packets 353265  bytes 466625001 (445.0 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 40284  bytes 2524665 (2.4 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

enp0s8: flags=4163  mtu 1500
        inet 192.168.10.11  netmask 255.255.255.0  broadcast 192.168.10.255
        inet6 fe80::a00:27ff:fea4:ebc7  prefixlen 64  scopeid 0x20
        ether 08:00:27:a4:eb:c7  txqueuelen 1000  (Ethernet)
        RX packets 17  bytes 3516 (3.4 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 138  bytes 21256 (20.7 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

enp0s8:1: flags=4163  mtu 1500
        inet 192.168.10.10  netmask 255.255.255.0  broadcast 192.168.10.255
        ether 08:00:27:a4:eb:c7  txqueuelen 1000  (Ethernet)

enp0s8:2: flags=4163  mtu 1500
        inet 192.168.10.101  netmask 255.255.255.0  broadcast 192.168.10.255
        ether 08:00:27:a4:eb:c7  txqueuelen 1000  (Ethernet)

enp0s8:3: flags=4163  mtu 1500
        inet 192.168.10.102  netmask 255.255.255.0  broadcast 192.168.10.255
        ether 08:00:27:a4:eb:c7  txqueuelen 1000  (Ethernet)

enp0s9: flags=4163  mtu 1500
        inet 192.168.20.11  netmask 255.255.255.0  broadcast 192.168.20.255
        inet6 fe80::a00:27ff:fe6b:7e0a  prefixlen 64  scopeid 0x20
        ether 08:00:27:6b:7e:0a  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 307  bytes 53396 (52.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

enp0s9:1: flags=4163  mtu 1500
        inet 169.254.98.147  netmask 255.255.0.0  broadcast 169.254.255.255
        ether 08:00:27:6b:7e:0a  txqueuelen 1000  (Ethernet)

lo: flags=73  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10
        loop  txqueuelen 0  (Local Loopback)
        RX packets 20397  bytes 46215763 (44.0 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 20397  bytes 46215763 (44.0 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

virbr0: flags=4099  mtu 1500
        inet 192.168.122.1  netmask 255.255.255.0  broadcast 192.168.122.255
        ether 52:54:00:09:73:ff  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

virbr0-nic: flags=4098  mtu 1500
        ether 52:54:00:09:73:ff  txqueuelen 500  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@rac12c01 network-scripts]#




[root@rac12c01 network-scripts]# ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp0s3: mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:73:f5:60 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic enp0s3
       valid_lft 85429sec preferred_lft 85429sec
    inet6 fe80::a00:27ff:fe73:f560/64 scope link
       valid_lft forever preferred_lft forever
3: enp0s8: mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:a4:eb:c7 brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.11/24 brd 192.168.10.255 scope global enp0s8
       valid_lft forever preferred_lft forever
    inet 192.168.10.10/24 brd 192.168.10.255 scope global secondary enp0s8:1
       valid_lft forever preferred_lft forever
    inet 192.168.10.101/24 brd 192.168.10.255 scope global secondary enp0s8:2
       valid_lft forever preferred_lft forever
    inet 192.168.10.102/24 brd 192.168.10.255 scope global secondary enp0s8:3
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fea4:ebc7/64 scope link
       valid_lft forever preferred_lft forever
4: enp0s9: mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:6b:7e:0a brd ff:ff:ff:ff:ff:ff
    inet 192.168.20.11/24 brd 192.168.20.255 scope global enp0s9
       valid_lft forever preferred_lft forever
    inet 169.254.98.147/16 brd 169.254.255.255 scope global enp0s9:1
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe6b:7e0a/64 scope link
       valid_lft forever preferred_lft forever
5: virbr0: mtu 1500 qdisc noqueue state DOWN
    link/ether 52:54:00:09:73:ff brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
6: virbr0-nic: mtu 1500 qdisc pfifo_fast master virbr0 state DOWN qlen 500
    link/ether 52:54:00:09:73:ff brd ff:ff:ff:ff:ff:ff
[root@rac12c01 network-scripts]# 




[root@rac12c01 network-scripts]# more /etc/hosts
127.0.0.1 localhost.localdomain localhost

# Public (eth1)
192.168.10.11 rac12c01.localdomain rac12c01
192.168.10.12 rac12c02.localdomain rac12c02
# Private (eth2)
192.168.20.11 rac12c01-priv.localdomain rac12c01-priv
192.168.20.12 rac12c02-priv.localdomain rac12c02-priv
# Virtual
192.168.10.101 rac12c01-vip.localdomain rac12c01-vip
192.168.10.102 rac12c02-vip.localdomain rac12c02-vip
# SCAN
192.168.10.10 scan12c.localdomain scan12c
[root@rac12c01 network-scripts]#


[root@rac12c01 network-scripts]# more /etc/resolv.conf
; generated by /usr/sbin/dhclient-script
nameserver 192.168.1.1
[root@rac12c01 network-scripts]#