Проблемы при обслуживании секционированных таблиц
В проекте управления архивными данными была использована опция 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, либо в лавинообразном росте сегмента глобального индекса таблицы с высококонкурентной вставкой.
Но это слишком сложная тема для первого рабочего дня в новом году. Опишу чуть позже.