Базы данных Oracle - статьи

         

Во что обходится обмен секций?


Давайте начнем с действительно простого случая- обмена таблицы из 1000000 строк с пустой секцией. Давайте начнем с SQL-операторов для создания секционированной таблицы и не секционированной таблицы - мы будем повторно использовать этот код, с некоторыми изменениями, в оставшейся части статьи. Нам также понадобится табличное пространство, в котором будет около 200 Мбайт свободного места.

create table parent ( id number(12,6), v1 varchar2(10), padding varchar2(100) ) partition by range(id) ( partition p1000 values less than (1000), partition p3000 values less than (3000), partition p5000 values less than (5000) );

create table parent_ex ( id number(12,6), v1 varchar2(10), padding varchar2(100)) nologging -- чтобы сэкономить немного времени ;

insert /*+ append ordered full(s1) use_nl(s2) */ into parent_ex select 3000 + trunc((rownum-1)/500,6), to_char(rownum), rpad('x',100) from sys.source$ s1, -- необходима соответствующая привилегия sys.source$ s2 where rownum <= 1000000;

А теперь давайте обменяем таблицу с секцией P5000, которой и принадлежат эти данные. Но давайте включим timing, чтобы увидеть, сколько времени на это потребуется.

alter table parent exchange partition p5000 with table parent_ex;

Elapsed: 00:00:17.06

Что произошло с "очень быстрым" переносом? Повторите тест с включенным sql_trace и вы обнаружите в трассировочном файле следующий SQL-оператор. Сервер Oracle проверяет, есть ли в таблице parent_ex строки, не принадлежащие указанной секции таблицы parent.

select 1 from "PARENT_EX" where TBL$OR$IDX$PART$NUM("PARENT",0,0,65535,"ID") != :1

Для этого необходимо выполнить полный просмотр таблицы и вызывать функцию для каждой строки в загружаемой таблице - представьте себе результат в реальной системе с большими объемами данных и загруженной подсистемой ввода-вывода.

Но не бойтесь, - именно для таких случаев предназначена конструкция without validation. Повторите эксперимент, но поместите в конце команды exchange эту конструкцию.


alter table parent exchange partition p5000 with table parent_ex without validation;

Elapsed: 00:00:00.00

Ур-ра - так работает намного быстрее! Но, не торопитесь с выводами; в реальных базах данных обычно есть индексы и ограничения первичного или уникального ключа. Поэтому давайте повторим упражнение, но добавим ограничение первичного ключа к основной и обмениваемой таблице перед обменом (Обратите внимание на синтаксис версии 9 для полного указания индекса при добавлении ограничения - я решил обеспечить выполнение ограничения уникального/первичного ключа с помощью уникального индекса). В этом случае, мы, вероятно, захотим включить в процесс обмена и индексы, чтобы данные оказались в основной таблице с пригодной к использованию секцией индекса.

alter table parent add constraint p_pk primary key(id) using index (create index p_pk on parent(id) nologging local);



alter table parent_ex add constraint px_pk primary key(id) using index (create index px_pk on parent_ex(id) nologging);

alter table parent exchange partition p5000 with table parent_ex including indexes without validation;

Elapsed: 00:00:28.05

А теперь что произошло? Повтор (не такой уж быстрый) эксперимента с включенным sql_trace выдает представленный ниже SQL-оператор. Сервер Oracle проверяет, что обмен не приведет к проблеме с уникальностью. Запрос просматривает всю таблицу parent (исключая секцию, которую мы обмениваем), чтобы узнать, нет ли дубликатов загружаемых нами строк. Это собенно глупо, поскольку ограничение уникальности поддерживается с помощью локального индекса, поэтому он обязательно включает ключ секционирования, а это означает, что строка может быть только в одной секции, и мы уже пообещали (с помощью конструкции without validation), что все строки принадлежат той секции, в которую мы их помещаем. Конечно, верно, что в других секциях могут быть строки, которые должны бы находиться в загружаемой секции, но и в этом случае я не думаю, что хочу тратить время на их поиск прямо сейчас.



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

Обратите внимание, в частности, на операторы minus и intersect

 - они требуют сортировки всего результирующего множества, и я ещё легко отделался со своими 28 секундами, поскольку (a) у меня не было данных в исходной таблице parent, и (b) данные в таблице parent_ex уже были отсортированы.

select "ID" from "TEST_USER"."PARENT_EX" where not( "ID" is null) intersect select "ID" from ( select "ID" from "TEST_USER"."PARENT" minus select "ID" from "TEST_USER"."PARENT" partition (P5000) ) B where not( "ID" is null)

Можно ли обойти эти огромные затраты? Да, и все, что нужно сделать - перевести ограничения по обеим таблицам в состяние novalidate перед выполнением обмена.

alter table parent_ex modify primary key novalidate; alter table parent modify primary key novalidate;

Общее назначение опции novalidate для ограничени - сообщить серверу Oracle, что он не должен проверять уже существующие данные, чтобы убедиться, что они соответствуют ограничению. Новые данные или изменения, которые вы будете делать в старых данных, будут, однако, проверяться, поскольку ограничение все равно действует.

Но тут есть очень тонкая скрытая ловушка. Существует специальный алгоритм оптимизатора, который оценивает стоимость ограничений первичного и уникального ключа ниже обычного, если только ограничение не допускает отложенную проверку или (как мы только что его установили) не находится в состоянии novalidate. Если мы изменим состояние ограничений с validate на novalidate, чтобы снизить затраты на обмен секций, мы можем обнаружить, что при этом случайный запрос начал выполняться иначе!

Так что, пожалуй, лучше оставить ограничения в состоянии validate, и не гнаться за "дешевизной", просто установив опцию without validation

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


Содержание раздела