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

В целях эксперимента привели обычную таблицу к секционированной путем выполнения alter table modify ... с интервальным партиционированием и статическими сабпартициями.

Существует ли метод вернуть ее в обратное состояние?

Просто не хочется восстанавливать DDL и копировать данные (долго и ресурсы требуются).


Ответы (2 шт):

Автор решения: 0xdb

У команды ALTER TABLE, обратного аналога клаузы modify_to_partitioned нет.

Одна из возможных алтернатив -- экспорт/импорт с опцией PARTITION_OPTIONS=merge.

Пример таблицы:

create table t1 (id int primary key, memo varchar2(16), created date)
partition by range (created) (
    partition t1_part_2020 values less than (date'2021-01-01'),
    partition t1_part_2021 values less than (maxvalue))
/
insert into t1 
    select rownum, 'memo row '||rownum, date'2020-01-01'+(rownum-1)
    from dual connect by level<=999
/    
commit;

select table_name, partitioned 
from user_tables where table_name='T1'
/
TABLE_NAME PARTITIONED 
---------- ------------
T1         YES         

Экспорт ничем не отличается, после таблицу надо удалить (не забудте про бэкап!!!):

$ expdp me/me@dbsrv/pdb1 directory=data_pump_dir tables=t1 dumpfile=t1.dmp logfile=exp.log
[...]
. . exported "ME"."T1":"T1_PART_2020"                    16.05 KB     366 rows
. . exported "ME"."T1":"T1_PART_2021"                    23.81 KB     633 rows
Master table "ME"."SYS_EXPORT_TABLE_01" successfully loaded/unloaded
******************************************************************************

SQL> drop table t1 cascade constraints purge;

Импорт с опцией для объединения партиций:

$ impdp me/me@dbsrv/pdb1 directory=data_pump_dir partition_options=merge \
  dumpfile=t1.dmp logfile=imp.log

Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
. . imported "ME"."T1":"T1_PART_2021"                    23.81 KB     633 rows
. . imported "ME"."T1":"T1_PART_2020"                    16.05 KB     366 rows

select table_name, partitioned 
from user_tables where table_name='T1'
/
TABLE_NAME PARTITIONED 
---------- ------------
T1         NO          
→ Ссылка
Автор решения: 0xdb

Другое решение -- реорганизовать таблицу онлайн помощью пакета DBMS_REDEFINITION, что позволит сократить время её недоступности (downtime) до нескольких минут.

Для этого, проверятся возможность реорганизации таблицы и создаётся внутренняя тблица со структурой целевой таблицы, в нашем случае без партиций:

exec sys.dbms_redefinition.can_redef_table (uname => 'db', tname => 't1')

create table intert1 (id int primary key, memo varchar2(16), created date)
/

Следуюшие шаги включают: запуск реорганизации, копирование всех зависимых объектов, контроль ошибок и, опционально, синхронизацию таблиц:

begin
    dbms_redefinition.start_redef_table (
    uname => 'me', 
    orig_table   => 't1',
    int_table    => 'intert1');
end;
/
declare
    numerr pls_integer;
begin
    dbms_redefinition.copy_table_dependents (
        uname            => 'me', 
        orig_table       => 't1',
        int_table        => 'intert1',
        copy_indexes     => dbms_redefinition.cons_orig_params, 
        copy_triggers    => true, 
        copy_constraints => true, 
        copy_privileges  => true, 
        ignore_errors    => true, 
        num_errors       => numerr);
    dbms_output.put_line ('errors='||numerr); 
end;
/
select object_name, base_table_name, ddl_txt 
from dba_redefinition_errors;

exec dbms_redefinition.sync_interim_table ( -
    uname => 'me', orig_table => 't1', int_table => 'intert1');

При завершении реорганизации целевая таблица будет заблокирована на несколько минут. Затем, она полностью соответствует по структуре внутренней таблице, и последняя может быть удалена:

exec dbms_redefinition.finish_redef_table ( -
    uname => 'me', orig_table => 't1', int_table => 'intert1');

select table_name, partitioned 
from user_tables where table_name='T1';

TABLE_NAME PARTITIONED 
---------- ------------
T1         NO          

drop table intert1 purge;
→ Ссылка