суббота, 21 января 2017 г.

Быстрый старт Oracle GG IExtract or IReplicat

Для быстрого старта Integrated Replicat или Extract в Oracle GG применяли такую оптимизацию internal SQL с помощью SQLPatch

DECLARE
    sql_text      clob := 'SELECT c.capture_name,      xo.queue_owner || ''.'' || xo.queue_name 
FROM all_xstream_outbound xo,all_capture c  WHERE xo.capture_name =
c.capture_name AND        server_name = SUBSTR(UPPER(''OGG$EXIEKS''),1,
30)'
;
    hints         VARCHAR2(1000) := 'PARALLEL(4)';
    description   VARCHAR2(100) := 'GG sql patch for IE';
    name          VARCHAR2(100) := 'GG_IE_SQL_PATCH';
    output        VARCHAR2(100);
    sqlpro_attr   sys.sqlprof_attr;
BEGIN
    sqlpro_attr := sys.sqlprof_attr(
        hints
    );
    output := sys.dbms_sqltune_internal.i_create_sql_profile(
        sql_text      => sql_text,
        profile_xml   => dbms_smb_internal.varr_to_hints_xml(
            sqlpro_attr
        ),
        name          => name,
        description   => description,
        category      => 'DEFAULT',
        creator       => 'SYS',
        validate      => true,
        type          => 'PATCH',
        force_match   => true,
        is_patch      => true
    );

    dbms_output.put_line(
        output
    );
END;
/

В итоге все запрос теперь выполняются с применением патча.


SELECT c.capture_name,       xo.queue_owner || '.' || xo.queue_name   FROM all_xstream_outbound xo, all_capture c  WHERE xo.capture_name =  c.capture_name AND        server_name = SUBSTR(UPPER('OGG$EXIEKS123'), 1,  30)
2017-01-15/11:43:21
GG_IE_SQL_PATCH
SELECT c.capture_name,       xo.queue_owner || '.' || xo.queue_name   FROM all_xstream_outbound xo, all_capture c  WHERE xo.capture_name =  c.capture_name AND        server_name = SUBSTR(UPPER('OGG$EXIEKS124'), 1,  30)
2017-01-15/11:43:52
GG_IE_SQL_PATCH
SELECT c.capture_name,       xo.queue_owner || '.' || xo.queue_name   FROM all_xstream_outbound xo, all_capture c  WHERE xo.capture_name =  c.capture_name AND        server_name = SUBSTR(UPPER('OGG$EXIEKS125'), 1,  30)
2017-01-15/11:43:58
GG_IE_SQL_PATCH


 Старт IExtract вместо 30 минут выполняется за 2 минуты после создания SQLPatch. 

воскресенье, 15 января 2017 г.

PlantUML


Сегодня через плагин к идее открыл для себя PluntUML. 
Крутота!
Я и не предполагал, что можно настолько удобно "изготавливать" или проектировать (термин "рисовать" совсем не подходит) в любом ТЕКСТОВОМ редакторе.

понедельник, 9 января 2017 г.

Проблемы при обслуживании секционированных таблиц

Проблемы при обслуживании секционированных таблиц


В проекте управления архивными данными была использована опция Oracle Partition. PSU - 11.2.0.4.7 Платформа - Oracle M6. SunOS 5.11

Столкнулись со следующими проблемами:

1. Unusable index segment not removed when index become unusable after partition operations
При выполнении операции alter table truncate partition/subpartition без опции update global indexes глобальные индексы должны были быть переведены в состояние UNUSABLE и удалены сегменты этих индексов. В состояние UNUSABLE индексы переведены, но сегменты не удалены. 
После этого перестроение индекса требует дополнительного пространства в TBS, т.к. при REBUILDе "старый" сегмент удаляется только после создания "нового". 
Проблема не очень большая, если размер индексов не велик. Но у нас размер одного глобального индекса доходит до 400G. И на для таких размеров поиск дополнительного свободного места в TBS - это уже проблема. 
Можно, конечно, придумать 1000 и 1 способ перестроения с выделением и дальнейшим освобождением использованного для перестроения места, но это все - дополнительные подпрыгивания, которых можно избежать, если перед  alter table truncate partition/subpartition  сделать alter index unusable.
Добавлю, что я не смог найти способа удалить существующий сегмент у unusable-индекса. Повторное изменение состояния на unusable не приводит к удалению существующего сегмента.

PS. Такое поведение выявлено для операции alter table truncate partition у субсекционированной таблицы. Возможно будет наблюдаться и в других вариантах операций обслуживания партиций.  

2. Alter table exchange partition stopped with error ORA-01407: cannot update ("SYS"."HIST_HEAD$"."COL#") to NULL
Исключение архивных данных из оперативной базы в проекте выполняется с помощью операции обмена секциями партиции с пустой таблицей. Делается это подобной командой:
ALTER /*+ MONITOR */ TABLE IBS.Z#DOCUM_RC EXCHANGE PARTITION (R_2015_10) WITH TABLE IBS.TT_J70NXQA2GAPKVTPNMJJA INCLUDING INDEXES WITHOUT VALIDATION UPDATE GLOBAL INDEXES  PARALLEL 128
Как видите, в exchange участвуют партиции локальных индексов.
В случае, если выполняются следующие условия:
- у секционированной таблицы присутствует функциональный индекс, 
- системные имена колонок функциональных индексов секционированной таблицы и таблицы, использующейся в exchange, отличаются (можно проверить в dba_ind_columns),
- по функциональному индексу собрана статистика,
то выполнение exchange завершится с ошибкой
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-01407: cannot update ("SYS"."HIST_HEAD$"."COL#") to NULL

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

Лечится удалением статистики с колонок функционального индекса перед операцией exchange. В моем случае пилюлька выглядит так:
exec                                       dbms_stats.delete_column_stats(ownname=>'IBS',tabname=>'Z#DOCUM_RC',colname=>'SYS_NC00169$');
exec                                       dbms_stats.delete_column_stats(ownname=>'IBS',tabname=>'Z#DOCUM_RC',colname=>'SYS_NC00168$');
exec                                       dbms_stats.delete_column_stats(ownname=>'IBS',tabname=>'TT_J70NXQA2GAPKVTPNMJJA',colname=>'SYS_NC00169$');
exec                                       dbms_stats.delete_column_stats(ownname=>'IBS',tabname=>'TT_J70NXQA2GAPKVTPNMJJA',colname=>'SYS_NC00170$');

3. Alter table exchange partition stopped with error ORA-19728: data object number conflict
Еще одна проблема с exchange. Возникает в случае одинаковых идентификаторов data_object_id у обменивающихся объектов.
В нас в проекте проблема возникла следующим образом:
- Была база данных с секционированным объектом.
- Создали копию этой базы и назвали ее архивом.
- Прошло какое-то время и теперь надо через transportable tbs перенести данные из оперативной БД в архив.
- В оперативной БД создаем "транспортную" таблицу и делаем exchange архивируемой партиции с этой таблицей. При exchange мы же просто делаем обмен сегментами, И в этом случае data_object_id у объекта не меняется. Т.о. мы получили транспортную таблицу с тем же самым data_object_id, что и соответствующая партиция в архивной БД.
- "Транспортную" таблицу мы не двигаем в другое TBS. (Заранее спроектировали хранение так, чтобы все лежало отдельно и не надо было заморачиваться с отделением архивных данных для переноса).
- Делаем экспорт TTBS в оперативной БД и импорт TTBS в архивной БД.
- Пытаемся "подключить" партицию в архивной БД в соответствующую таблицу с помощью exchange и получаем
ALTER /*+ MONITOR */ TABLE IBS.Z#MBK_ACQ EXCHANGE PARTITION (R_2016_04) WITH TABLE IBS.TT_8ZINLFCFCLIF2L1RFJNG INCLUDING INDEXES WITHOUT VALIDATION;
ERROR at line 1:
ORA-19728: data object number conflict between table TT_8ZINLFCFCLIF2L1RFJNG and partition R_2016_04_C_000 in table Z#MBK_ACQ 

Способов решения проблемы много. Все они сводятся к изменению data_object_id либо у партиции, либо у "транспортной" таблицы. 
Можно сделать move.
Но я выбрал truncate partition в архивной таблице, т.к. эти данные мне уже не нужны. Они будут замещены данными из транспортной таблицы. И к тому же в партиция архивной таблицы большая и Move будет выполняться долго.
Но для truncate пришлось на время отключить FK на таблицу, в которой делал truncate partition.
Кроме этого, если делаем truncate пустой партиции, то data_object_id не меняется. Парни в Oracle тоже не хотят делать лишние движения. Так что для "надежности" после truncate я еще и move таки делаю.
То что после truncate и move становятся unusable глобальные индексы, меня не волнует.  Я так и так собираюсь их перестраивать после exchange. 

4. TX-index contention or index unformated blocks after delete operation
У операции exchange, выполняемой с опцией update global indexes, нашлась еще одна БОЛЬШАЯ проблема. И выражается эта проблема либо в возникновении TX-index contention после выполнения exchange, либо в лавинообразном росте сегмента глобального индекса таблицы с высококонкурентной вставкой.
Но это слишком сложная тема для первого рабочего дня в новом году. Опишу чуть позже.