понедельник, 12 ноября 2018 г.

Oracle Warehousing: копирование таблицы через dblink

Необходимо из таблицы table_remote@dblink объемом 270 ГБ, выбрать только лишь те строки, которые соответствуют строкам из локальной таблицы table_dict.  Результат выборки сохранить в локальную таблицу table_local. Предварительные выборки показали, что результат составит примерно 100 МБ.

На локальном сервере создаём таблицу (table_local), затем, используя анонимный PL/SQL блок и курсор, загружаем отфильтрованные данные из table_remote@dblink:

DECLARE 
  CURSOR cr_data IS 
    SELECT 
           /*+ driving_site(tr)*/ 
           tr.* 
    FROM   table_remote@dblink tr 
    join   table_dict td 
    ON     ( tr.col_1 = td.col_2); 

  TYPE t_cr_row IS TABLE OF cr_data%ROWTYPE; 
  v_cr_row t_cr_row; 
BEGIN 
  OPEN cr_data; 
  LOOP 
    FETCH cr_data BULK COLLECT 
    INTO  v_cr_row limit 10000; 
     
    EXIT WHEN v_cr_row.count = 0; 
    FORALL i IN 1..v_cr_row.count 
    INSERT INTO table_local VALUES v_cr_row(i); 
     
    COMMIT; 
  END LOOP; 
  CLOSE cr_data; 
END;
/

В этом варианте решения следует принять во внимание то, что в списке полей таблицы table_remote@dflink  не должно быть LOB-полей. LOB-поля не возможно выбирать по dblink. При такой попытке возникает ошибка ORA-22992: cannot use LOB locators selected from remote tables. 
Для копирования remote таблиц c LOB-полями необходимо создавать промежуточные таблицы методом CTAS  (CREATE TABLE AS SELECT).

Рассмотрим другие варианты решения этой задачи.

1. На локальном сервере запускаем команду на создание промежуточной таблицы с выборкой данных и соединением таблиц - CTAS:

   CREATE TABLE table_local AS 
  SELECT /*+ driving_site(tr)*/ tr.* 
  FROM   table_remote@dblink tr 
         join table_dict td 
           ON ( tr.col_1 = td.col_2 ); 
   
Используя хинт driving_site мы просим СУБД выполнить соединение таблиц на удаленном сервере, предполагая, что переправка данных таблицы table_dict займет меньше времени, чем переправка данных таблицы table_remote@dblink объёмом 270 ГБ. Но это решение не будет работать, потому что хинт driving_site в DDL  не будет функционировать.
   
2. На локальном сервере создаём таблицу, затем используя INSERT, загружаем отфильтрованные данные из table_remote@dblink :

INSERT INTO table_local 
SELECT /*+ driving_site(tr)*/ tr.* 
FROM   table_remote@dblink tr 
       join table_dict td 
         ON ( tr.col_1 = td.col_2 );  

Это решение также не является оптимальным по той же причине - хинт driving_site не будет работать в DML.

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

Oracle Warehousing: осторожно, MERGE

MERGE используется для компактной реализации логики "нет строки - вставляем, есть - обновляем (удаляем)". В Warehousing с помощью такой команды можно добавлять инкремент в витрину. Но так ли уж полезен MERGE при больших объёмах данных?
MERGE можно использовать для обновления данных в колонках большой таблицы, выбирая данные из нескольких других не маленьких таблиц (или одной, как показано в примере ниже).  
Вот как можно это сделать:



Для соединения целевой таблицы и источника, в котором участвует целевая таблица для выборки данных, используем rowid этой же таблицы. Важно в блоке USING использовать псевдоним к rowid, иначе возникнет ошибка при выполнении MERGE. Эта ошибка не описывается в документации и не предлагается решения для её устранения. Экспериментальным путём было установлено, что надо использовать псевдоним.

При использовании MERGE для вставки данных, используя большие таблицы не обойтись без хинтов PARALLEL и APPEND, иначе будет медленно выполняться команда. Но при использовании этих хинтов, следует принять во внимание очень плохие последствия. При  выполнении команды INSERT в таблицу будут добавляться новые экстенты и это будет приводить к увеличению размера таблицы не соразмерно объёму данных в ней.
Выполним следующий скрипт и соберём статистику, посмотрим сколько места занимает таблица.

























Для хранения 100 строк таблице был выделен один экстент, в котором 8 блоков, каждый объёмом в 16 КБ . 
Теперь выполним MERGE c хинтом APPEND, соберём статистику и проверим сколько места теперь стала занимать таблица:


В таблицу добавилась одна строка и был выделен еще один экстент. Теперь таблица стала занимать места в два раза больше: 2 экстента с 16 блоками.
Тот же результат будет получен, если использовать хинт PARALLEL с предварительно выполненной командой: alter session enable parallel dml;































Увеличение размера таблицы - актуальная проблема для Warehousing с партицированными таблицами.

воскресенье, 23 сентября 2018 г.

Oracle Warehousing: создание таблиц для тестирования

Тема тестирования задач Warehousing весьма обширная и нетривиальная. Здесь речь пойдет о создании таблиц с целью протестировать свой скрипт перед тем, как отдать этот скрипт на ревью.
Тестировать скрипт придется либо в тестовой среде либо в своей персональной схеме в продуктовой среде.
В тестовой среде будет хилый сервер и маленький объём данных. Не стоит рассчитывать на качественное тестирование на маленьких объёмах данных.
В продуктовой среде в своей персональной схеме будут другие ограничения. Во-первых, полный доступ только к своим объектам, которые созданы в своей схеме, к остальным объектам доступ только на чтение. Во-вторых, в нашем расположении будет небольшой доступный объём места на диске для создания таблиц (и индексов) и наполнения их данными, например, 20Гб. Если размер таблицы, которую необходимо скопировать больше 20 Гб, то можно скопировать какой-либо её раздел (partition).
При тестировании в продуктовой среде необходимо будет создать несколько таблиц в своей схеме и проводить над ними DML операции, отмечая время выполнения каждой из них.
Объем информации, который можно записать в своей схеме можно узнать из представления dba_ts_quotas по имени своего пользователя.





max_bytes - указывает на максимальный выделенный объём в байтах в своей схеме;
bytes - указывает на то, сколько байт уже занято;

Так же из этого представления можно узнать наименование tablespace, в котором будут создаваться таблицы и индексы. У tablespace есть ограничение на объём информации и это надо обязательно учитывать, когда собираемся создать копию таблицы. Доступный объём можно узнать из следующего запроса:



















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







В том случае, если эти функции включены, то при создании таблиц для тестирования следует отключать их:



Если в создаваемой тестовой таблице данные не планируется обновлять, обязательно указываем pctfree 0. Таким образом мы сэкономим место на диске. Если данные в тестовой таблице будут изменяться, то можно задать pctfree 2.
Для оценки времени выполнения скрипта, вполне достаточно перенести в свою схему только одну партицию огромной таблицы. Оценить время выполнения скрипта на одной партиции и увеличив это время на количество партиций, можно получить примерное время выполнения скрипта над всеми разделами таблицы. Если при обновлении данных будут использоваться индексы, то необходимо также создать их в тестовой таблице.
По окончании тестирования в продуктовой среде необходимо удалить свои тестовые таблицы с опцией purge. Или если забыли дописать эту опцию к drop, необходимо выполнить дополнительную команду: purge recyclebin.

понедельник, 3 сентября 2018 г.

Oracle Warehousing: создание разделов в таблице (table partitions)

Задача: необходимо создать разделы (partitions) в существующей таблице, заполненной данными объемом 14 ГБ, строк - 67 миллионов, в ней есть 5 индексов. Разделов должно получится 150. В дальнейшем, в этой таблице разделы будут создаваться с помощью хранимых процедур.

Решение.
Стоит упомянуть, что весь код для решения задачи нельзя размещать в одном файле скриптов. Необходимо распределять код по разным файлам. Любой файл скриптов можно запустить более одного раза с одним и тем же успешным результатом (кроме файла с DDL командами, обычно этот файл называется alter.sql). Файлы скриптов будут запускаться в том же порядке, в котором они описаны далее в этой статье.
  1. Файл create.sql : здесь мы создаем одноименную таблицу, но с каким-либо суффиксом, например, _new. Обязательно с опцией ENABLE ROW MOVEMENT.
  2. Файл grant.sql : здесь мы даем права на новую таблицу ролям или другим пользователям.
  3. Файл alter.sql : здесь мы создаем пустые разделы в новой пустой таблице, переименовываем constraints и indexes в существующей таблице. Все indexes и constraints в коде не приводятся ради экономии места.
  4. Файл long_operation.sql : здесь мы с помощью INSERT вставляем строки из существующей таблицы в созданную нами таблицу, создаем в новой таблице indexes и constraints (indexes создаем в параллели), собираем статистику по новой таблице, переименовываем существующую таблицу, добавляя суффикс _old, переименовываем новую таблицу, убирая суффикс _new.