5 августа 2008 г.

Ожидания при чтении и записи LOBов

Вчера я пыталась создать копию таблицы, у которой был столбец типа BLOB. Заливка данных повисла, и я оставила ее висеть до утра :D К тому же это было не к спеху. Таблица была средненькая: около 700 тыс. записей, весит 2 гига. Знала, что это из-за LOBа так висит, и сегодня решила докапаться до истины. И так все по-порядку.

Сперва пыталась создать копию таблицы обычным "create table ... as select", думала средненькая таблица скопируется быстро, но не тут-то было. Висела больше часа, пока не кильнула сессию. С опцией nologging тоже самое, через несколько часов и ее убила:

create table new_blob_table as select * from orig_blob_table;

create table new_blob_table nologging as select * from orig_blob_table;
А direct path insert командой insert /*+ append */ тоже висела пару часов, и я, добрая, оставила ее висеть до утра:
create table new_blob_table as select * from orig_blob_table where 1=2;

insert /*+ append */ into new_blob_table select * from orig_blob_table;
Во время всех этих попыток, сессия ожидала события direct path write (lob):
SQL> select event
from v$session_wait
where sid=969;

EVENT
-------------------------
direct path write (lob)
При прямой записи - direct path write - запись происходит В ОБХОД буферного кеша прямо в файлы данных. Запись выполняется серверным процессом (а не процессом DBWR, как в обычной записи), который в pga сессии подготавливает блоки и записывать их за отметкой HWM.

Бурлесон перечисляет список операций, которые могут выполнять операцию прямой записи (direct path write) и вызывать соответствущие ожидания:
Operations that could perform direct path writes include when
1) a sort goes to disk,
2) during parallel DML operations,
3) direct-path inserts,
4) parallel create table as select, and
5) some LOB operations.
Наш случай - последний, связанный с LOBами. Вот что пишут в документации Oracle о прямой записи (direct path write) и параметре CACHE/NOCACHE LOB-сегментов:
With the CACHE option, LOB data reads show up as wait event 'db file sequential read', writes are performed by the DBWR process.

With the NOCACHE option, LOB data reads/writes show up as wait events:
direct path read (lob)/direct path write (lob).

Corresponding statistics are:
physical reads direct (lob) and physical writes direct (lob).
О параметре CACHE BLOB-сегментов, я писала недавно здесь. Получается, что когда я создавала таблицу командой create table ... as select ..., LOB-сегмент таблицы создались с параметром NOCACHE, который и ведет к ожиданиям direct path write (lob).
SQL> select table_name, column_name, cache
from dba_lobs
where table_name='NEW_BLOB_TABLE';

TABLE_NAME COLUMN_NAME CACHE
-------------------- -------------------- --------
NEW_BLOB_TABLE BLOB_COLUMN NO
То есть новую таблицу нужно либо изначально создать с параметром CACHE LOB-сегмента:
create table new_blob_table
lob (blob_column) store as (cache)
as select * from orig_blob_table where 1=2;
или после создания пустой таблицы (where 1=2), изменить параметр CACHE LOB-сегмента:
alter table new_blob_table modify lob (request_content) (cache);
Теперь, заливка длится чуть больше 1 минуты (!!!):
SQL> create table new_blob_table
lob (blob_column) store as (cache)
as select * from orig_blob_table where 1=2;

Table created.

SQL> set timing on
SQL> insert /*+ append */ into new_blob_table select * from orig_blob_table;

642966 rows created.

Elapsed: 00:01:12.83
Даже обычный инсерт отработал всего 4 минуты!
SQL> insert into new_blob_table select * from orig_blob_table;

642966 rows created.

Elapsed: 00:04:18.85
Странно, что если создавать НЕпустую таблицу командой create table ... as select ... с параметром CACHE LOB-сегмента, он все равно зависает с ожиданиями direct path write (lob):
create table new_blob_table
lob (blob_column) store as (cache)
as select * from orig_blob_table;
Теперь, при заливке командой insert /*+ append */, ожидания записи direct path write (lob) исчезли, есть коротенькие ожидания, но это уже ожидания чтения db file sequential read и db file scattered read. А статистика physical writes direct (lob) заменилась на physical writes direct.

Вот. Получается, что с insert /*+ append */ происходит прямая запись, но видимо эта запись уже отличается прямой записи БЛОБов. Если у кого-то есть более подробное описание всего этого, буду рада послушать.

1 коммент.:

Unknown комментирует...

Данной решение подходит для случая когда размер LOB-а менее 4000Bytes и LOB-полей НЕМНОГО в таблице.
С большими LOB или c большим количеством небольших LOB ситуация была бы другая - быстрее работал бы режим NOCACHE
Если время заливки очень критично можно еще попробовать режим NOCACHE NOLOGGING:
alter tabe table_name modify lob (LOB_column_name) (nocache nologging)
- размер сгененрированного REDO значительно уменьшится :)

Кстати, в статье не указано какой режим использовался для хранения LOB(ENABLE/DISABLE ) - это тоже важно. Но, кажется, :) - DISABLE STORAGE IN ROW. Для ENABLE STORAGE IN ROW изменение параметра CACHE/NOCACHE не повлияло бы на производительность в данном случае.