Как правильно очистить табличное пространство?
Например, у нас есть таблица с несколькими миллионами строк и функциональными индексами. Мы хотим удалить большую часть таблицы.
Для этого мы вызвали: удалить из какой-то_таблицы, где ....
Какие следующие шаги?
Эта последовательность правильная? 1. Отбросьте функциональные показатели. 2. Измените размер таблицы some_table. 3. Снова создайте функциональные индексы.
@MansiRaval Я думаю, вы, возможно, упустили суть вопроса ОП. Вы не можете использовать alter table...shrink space
для таблицы с индексами на основе функций. Не допускается (ORA-10631).
Да, я не могу уменьшить таблицу с функциональными индексами
Как вы, вероятно, поняли (или вы бы не спрашивали, в частности, об индексах на основе функций), вы не можете просто:
alter table mytable enable row movement;
alter table mytable shrink space;
alter table mytable disable row movement;
Попытка сделать это приведет к:
ORA-10631: SHRINK clause should not be specified for this object
(Примечание: это ограничение также относится к индексам соединения растровых изображений.)
Очевидно, вы можете сначала бросить ФБР...
drop index my_fbi_index;
alter table mytable enable row movement;
alter table mytable shrink space;
alter table mytable disable row movement;
create index my_fbi_index... online;
Однако это не онлайн-операция. На ваше приложение (я) на короткое время повлияет отсутствие индекса на основе функций.
Если вам нужна онлайн-операция и вы используете Oracle 12.2 или более позднюю версию, вы можете попробовать это вместо этого:
alter table mytable move online;
(alter table...move
(без «в сети») доступно до версии 12.2, но это не онлайн-операция, и она удалит ваши сегменты индекса, оставив индексы с пометкой «непригодные для использования» и потребовав их перестроения. Так что не очень хороший вариант до -12.2.)
Создайте новая таблица только с действительными данными и пересоздать индексы туда, затем удалите старую таблицу.
RANGE (ENDEDAT) INTERVAL ( NUMTODSINTERVAL(1,''day'') ) ( PARTITION p_first VALUES LESS THAN ( TO_DATE(''01-01-2010'',''dd-MM-yyyy'') ) ) ENABLE ROW MOVEMENT
sqlCommand := 'create table ' || table_name ||'_TMP
tablespace &TBS_NORMAL_TABLES initrans 32 ' || partitionText ||'
nologging
AS (SELECT * FROM '||table_name|| ' ' ||filter_text||')';
EXECUTE IMMEDIATE sqlCommand;
Например, ограничения, индексы... Их можно собрать из встроенных таблиц, таких как all_constraints, all_indexes. Перемещение атрибутов также можно автоматизировать, просто нужно применить некоторые приемы переименования.
execute immediate 'ALTER TABLE &Schemaowner..'||v_table_name||' RENAME TO '||v_table_name||'_OT';
execute immediate 'ALTER TABLE &Schemaowner..'||v_table_name||'_TP'||' RENAME TO '||v_table_name;
execute immediate 'DROP TABLE '||v_table_name||'_OT';
Вот некоторая информация и полезные ссылки о моем расследовании, когда рассматривалось архивирование огромного количества данных в действующих БД.
for i in (SELECT obj.owner,obj.table_name,(CASE WHEN NVL(idx.cnt, 0) < 1 THEN 'Y' ELSE 'N' END) as shrinkable, row_movement
FROM all_tables obj,
(SELECT table_name, COUNT(rownum) cnt
FROM user_indexes
WHERE index_type LIKE 'FUN%'
GROUP BY table_name) idx
WHERE obj.table_name = idx.table_name(+)
AND obj.owner = &Schemaowner
and obj.table_name like 'T_%' and obj.table_name not like 'TMP_%'
and NVL(idx.cnt,0) < 1)
loop
BEGIN
if i.row_movement='ENABLED' then
execute immediate 'alter table '||i.table_name||' shrink space';
else
execute immediate 'alter table '||i.table_name||' enable row movement';
execute immediate 'alter table '||i.table_name||' shrink space';
execute immediate 'alter table '||i.table_name||' disable row movement';
end if;
DBMS_OUTPUT.PUT_LINE('shrinked table: ' || i.table_name);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('error while shrinking table: ' || i.table_name);
DBMS_OUTPUT.PUT_LINE (SQLERRM);
DBMS_OUTPUT.PUT_LINE (SQLCODE);
if SQLCODE=-10635 then
for p in (SELECT partition_name ,tablespace_name FROM user_tab_partitions WHERE table_name = 'SOME_PARTITIONED_TABLE')
loop
BEGIN
execute immediate 'alter table '||i.table_name||' MOVE PARTITION ' || p.partition_name || ' ONLINE TABLESPACE ' || p.tablespace_name || ' COMPRESS UPDATE INDEXES';
DBMS_OUTPUT.PUT_LINE('moved partition: ' || p.partition_name);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('error while moving partition: ' || p.partition_name);
DBMS_OUTPUT.PUT_LINE (SQLERRM);
DBMS_OUTPUT.PUT_LINE (SQLCODE);
CONTINUE;
END;
end loop;
end if;
CONTINUE;
END;
end loop;
SELECT obj.owner
,obj.table_name
,(CASE WHEN NVL(idx.cnt, 0) < 1 THEN 'Y' ELSE 'N' END) as shrinkable
FROM all_tables obj,
(SELECT table_name, COUNT(rownum) cnt
FROM user_indexes
WHERE index_type LIKE 'FUN%'
GROUP BY table_name) idx
WHERE obj.table_name = idx.table_name(+)
AND NVL(idx.cnt,0) < 1
and obj.owner='YOUR_SCHEMA_OWNER'
SELECT *
FROM all_indexes
WHERE index_type LIKE 'FUN%'
and owner='YOUR_SCHEMA_OWNER'
SELECT obj.owner
,obj.table_name
,(CASE WHEN NVL(idx.cnt, 0) < 1 THEN 'Y' ELSE 'N' END) as shrinkable
FROM all_tables obj,
(SELECT table_name, COUNT(rownum) cnt
FROM user_indexes
WHERE index_type LIKE 'FUN%'
GROUP BY table_name) idx
WHERE obj.table_name = idx.table_name(+)
AND NVL(idx.cnt,0) < 1
--and obj.table_name like 'T_%' and obj.table_name not like 'TMP_%'
and obj.compression != 'ENABLED'
and obj.table_name not in (SELECT table_name FROM user_tab_partitions WHERE compression = 'ENABLED')
and obj.owner='YOUR_SCHEMA_OWNER'
SELECT table_name,compression, compress_for FROM user_tables WHERE compression = 'ENABLED'
SELECT table_name,partition_name, compression, compress_for FROM user_tab_partitions WHERE compression = 'ENABLED' ORDER BY 1
select segment_name,bytes/1024/1024 as mb,blocks from user_segments where segment_name='TABLE_NAME'
В моем случае я создаю таблицу (не разделенную) с парой миллионов строк, затем удаляю 1/3 ее, вот результаты:
|| BYTES || BLOCKS ||
Before deletion || 105250816 || 12848 ||
After deletion || 78774272 || 9616 ||
Возможные побочные эффекты https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:9536157800346457013
... и когда следует использовать reorg: http://www.dba-oracle.com/t_table_fragmentation.htm
... включить движение строк, в то время как сжимать пространство может изменить порядок строк (это означает, что если использовать задания на основе ROWID или выборки или что-то в этом роде, могут быть некоторые сюрпризы)
http://www.dba-oracle.com/t_enable_row_movement.htm
Вы предоставили только набор операторов SELECT, но ни одного оператора, который фактически сжимает данные.
Какие следующие шаги? - спросил он, я пытаюсь помочь ему понять, с чем он сталкивается :( . Также до меня куча людей написала уменьшающий DDL, я просто хочу поместить сюда некоторые другие полезные данные
DBMS_REDEFINITION
, если вы хотите следовать этому подходу, так как он справится с большей частью этого за вас.
@MatthewMcPeak в другом ответе также напишите несколько шагов для этого случая, но да, я должен представить пример
@MatthewMcPeak я отредактировал свой комментарий, чтобы немного продемонстрировать оба способа
имеет недостаток, во время этой операции (которая может занять некоторое время) ваше приложение недоступно.
Итак, ваш подход
верно.
Если у вас есть секционированная таблица, см. эту: https://dba.stackexchange.com/questions/162415/how-to-shrink-space-on-table-with-a-function-based-index
Есть еще один вариант, который я не видел, чтобы кто-то предлагал. Выполните DELETE, затем ничего не делайте. ПОЧЕМУ мы думаем, что нам нужно перестроить индекс? ПОЧЕМУ мы думаем, что нам нужно изменить размер таблицы? Если мы ничего не делаем после DELETE, все экстенты для таблицы остаются выделенными для таблицы и БУДЕТ использоваться при будущих ВСТАВКАХ. Если у вас есть розничный магазин и вы проводите распродажу, в результате чего на полках остается много пустых полок, перестраиваете ли вы магазин, чтобы убрать «пустое» пространство? Или вы просто повторно используете пустые полки по мере поступления новых товаров? Что можно получить, изменив размер таблицы? В лучшем случае это освободит место обратно в TS, а не в файловую систему ОС. Хотя есть варианты использования, которые приводят доводы в пользу изменения размера таблицы, это НЕ является автоматическим, учитывая, что изменение размера после большого (даже массивного) DELETE обязательно оправдано.
Итак, еще раз, мой ответ - ничего не делать после DELETE (ну, конечно, сделать COMMIT!)
Я думаю, что нет необходимости сбрасывать индексы, если вы собираетесь его использовать. используйте приведенную ниже команду для перестроения индекса alter table mytable move; Также для освобождения места: alter table mytable разрешает перемещение строк; изменить таблицу mytable сжать пространство;