Как очистить неиспользуемое пространство после удаления строк в таблице с функциональными индексами?

Как правильно очистить табличное пространство?

Например, у нас есть таблица с несколькими миллионами строк и функциональными индексами. Мы хотим удалить большую часть таблицы.

Для этого мы вызвали: удалить из какой-то_таблицы, где ....

Какие следующие шаги?

Эта последовательность правильная? 1. Отбросьте функциональные показатели. 2. Измените размер таблицы some_table. 3. Снова создайте функциональные индексы.

Я думаю, что нет необходимости сбрасывать индексы, если вы собираетесь его использовать. используйте приведенную ниже команду для перестроения индекса alter table mytable move; Также для освобождения места: alter table mytable разрешает перемещение строк; изменить таблицу mytable сжать пространство;

Mansi Raval 17.07.2019 15:34

@MansiRaval Я думаю, вы, возможно, упустили суть вопроса ОП. Вы не можете использовать alter table...shrink space для таблицы с индексами на основе функций. Не допускается (ORA-10631).

Matthew McPeak 17.07.2019 16:11

Да, я не могу уменьшить таблицу с функциональными индексами

Kirill Kobyshev 17.07.2019 16:25
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
3
3 031
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

  1. создать таблицу выберите * из старой таблицы, где...
  2. удалить старый стол
  3. переименовать newtable в oldtable
  4. пересоздать индексы.
Ответ принят как подходящий

Как вы, вероятно, поняли (или вы бы не спрашивали, в частности, об индексах на основе функций), вы не можете просто:

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.)

Лучший способ

Создайте новая таблица только с действительными данными и пересоздать индексы туда, затем удалите старую таблицу.

  • Создайте новую таблицу с отфильтрованными данными, где table_name — это имя таблицы, filter_text — это условие, начинающееся с «ГДЕ…», а partitionText — это предложение разделения, если оно у вас есть для таблицы, например 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';

TL;DR информация о сжатии и реорганизации таблиц

Вот некоторая информация и полезные ссылки о моем расследовании, когда рассматривалось архивирование огромного количества данных в действующих БД.

Автоматизированный способ сжатия некоторых таблиц и обработки ошибок в них.

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, но ни одного оператора, который фактически сжимает данные.

Wernfried Domscheit 17.07.2019 16:50

Какие следующие шаги? - спросил он, я пытаюсь помочь ему понять, с чем он сталкивается :( . Также до меня куча людей написала уменьшающий DDL, я просто хочу поместить сюда некоторые другие полезные данные

Levente Takács 17.07.2019 16:54
Создайте новую таблицу только с действительными данными и воссоздайте там индексы, а затем удалите старую таблицу.. А затем переименуйте новую таблицу в старую, потом, я думаю. Этот подход приведет к поломке многих приложений, если вы также не будете учитывать гранты, политики VPD, триггеры и т. д. Подумайте DBMS_REDEFINITION, если вы хотите следовать этому подходу, так как он справится с большей частью этого за вас.
Matthew McPeak 17.07.2019 16:55

@MatthewMcPeak в другом ответе также напишите несколько шагов для этого случая, но да, я должен представить пример

Levente Takács 17.07.2019 17:06

@MatthewMcPeak я отредактировал свой комментарий, чтобы немного продемонстрировать оба способа

Levente Takács 17.07.2019 17:32
  • Создайте копию своей таблицы
  • Удалить старую таблицу
  • Переименовать копию

имеет недостаток, во время этой операции (которая может занять некоторое время) ваше приложение недоступно.

Итак, ваш подход

  1. Отбросьте функциональные индексы.
  2. Измените размер таблицы some_table.
  3. Снова создайте функциональные индексы.

верно.

Если у вас есть секционированная таблица, см. эту: https://dba.stackexchange.com/questions/162415/how-to-shrink-space-on-table-with-a-function-based-index

Есть еще один вариант, который я не видел, чтобы кто-то предлагал. Выполните DELETE, затем ничего не делайте. ПОЧЕМУ мы думаем, что нам нужно перестроить индекс? ПОЧЕМУ мы думаем, что нам нужно изменить размер таблицы? Если мы ничего не делаем после DELETE, все экстенты для таблицы остаются выделенными для таблицы и БУДЕТ использоваться при будущих ВСТАВКАХ. Если у вас есть розничный магазин и вы проводите распродажу, в результате чего на полках остается много пустых полок, перестраиваете ли вы магазин, чтобы убрать «пустое» пространство? Или вы просто повторно используете пустые полки по мере поступления новых товаров? Что можно получить, изменив размер таблицы? В лучшем случае это освободит место обратно в TS, а не в файловую систему ОС. Хотя есть варианты использования, которые приводят доводы в пользу изменения размера таблицы, это НЕ является автоматическим, учитывая, что изменение размера после большого (даже массивного) DELETE обязательно оправдано.

Итак, еще раз, мой ответ - ничего не делать после DELETE (ну, конечно, сделать COMMIT!)

Другие вопросы по теме