Вы находитесь на странице: 1из 6

В обычных (Regular) секционированных таблицах Oracle возможна настройка

автосоздания новых секций (без автоудаления старых).

В индекс-организованных таблицах (IOT) не поддерживается автосоздание новых


секций.

Для автоматизации настройки автосоздания новых/автоудаления старых секций в


IOT следует (на примере IOT с суточными секциями по дате, собранными в месячные
tablespace с собственным файлом данных, т.е. в 1 файле 1 tablespace с 28-31 секцией):

1. Если IOT имеются только в 1 пользовательской схеме, то все работы по


управлению секциями оставить в ней. Если таких схем несколько, то для
управления секциями лучше создать отдельную схему с соответствующими
правами.
2. В выбранной схеме создать хранимый пакет (Package) с процедурами
контроля/создания/удаления секций.
3. В выбранной схеме создать плановую задачу (Scheduler Job), выполняющую
основную процедуру пакета управления.

Скрипт создания схемы IOT_MANAGER и выделения ей необходимых прав:

-- Create the user


create user IOT_MANAGER
identified by IOT_MANAGER_PASSWORD
default tablespace USERS
temporary tablespace TEMP
profile DEFAULT
quota unlimited on ts_trc_dat
quota unlimited on ts_trc_idx;
-- Grant/Revoke object privileges
grant select on DBA_DATA_FILES to IOT_MANAGER;
grant select on DBA_IND_PARTITIONS to IOT_MANAGER;
grant select on DBA_TAB_PARTITIONS to IOT_MANAGER;
grant read, write on directory ORACLE_DATA_FILES to IOT_MANAGER;
grant execute on UTL_FILE to IOT_MANAGER;
-- Grant/Revoke system privileges
grant alter any table to IOT_MANAGER;
grant alter database to IOT_MANAGER;
grant alter user to IOT_MANAGER;
grant create session to IOT_MANAGER;
grant create tablespace to IOT_MANAGER;
grant drop any table to IOT_MANAGER;
grant drop tablespace to IOT_MANAGER;

Скрипт создания пакета PCK_IOT:

CREATE OR REPLACE PACKAGE PCK_IOT IS

-- Author : EV.GORLOV
-- Created : 01.01.2020
-- Purpose : Удаление старых и создание новых структур (ежемесячных
файл-tablespace и ежесуточных секций в них) в IOT

-- Public type declarations


--type <TypeName> is <Datatype>;

-- Public constant declarations


--<ConstantName> constant <Datatype> := <Value>;
-- Public variable declarations
--<VariableName> <Datatype>;

-- Public function and procedure declarations


--function <FunctionName>(<Parameter> <Datatype>) return <Datatype>;

-- Ручной перебор всех IOT для проверки


PROCEDURE PRC_CHK_ALL_IOT;

END;

CREATE OR REPLACE PACKAGE BODY PCK_IOT IS

-- Private type declarations


--type <TypeName> is <Datatype>;

-- Private constant declarations


--<ConstantName> constant <Datatype> := <Value>;
const_month_cnt integer := 3*12; -- заданный размер архива [месяцы]

-- Private variable declarations


--<VariableName> <Datatype>;

-- Function and procedure implementations


/*
function <FunctionName>(<Parameter> <Datatype>) return <Datatype> is
<LocalVariable> <Datatype>;
begin
<Statement>;
return(<Result>);
end;
*/

-- Логирование событий
procedure PRC_Trace_Log(v_Message in HIST_LOGS.MESSAGE%Type,
v_dt in HIST_LOGS.DT%Type default sysdate) is
PRAGMA AUTONOMOUS_TRANSACTION;
begin
insert into Hist_Logs
(Message,
DT)
values
(v_Message,
v_dt);
commit;
end;

-- convert HIGH_VALUE column to a date


FUNCTION FN_PART_HV_TO_DATE(p_table_owner IN
DBA_TAB_PARTITIONS.table_owner%Type,
p_table_name IN
DBA_TAB_PARTITIONS.table_name%Type,
p_partition_name IN
DBA_TAB_PARTITIONS.partition_name%Type)
RETURN DATE is
-- --------------------------------------------------------------------------
---------
-- File Name : https://oracle-
base.com/dba/miscellaneous/part_hv_to_date.sql
-- Author : Tim Hall
-- Description : Create a function to turn partition HIGH_VALUE column to a
date.
-- Call Syntax : @part_hv_to_date
-- Last Modified: 19/01/2012
-- Notes : Has to re-select the value from the view as LONG cannot be
passed as a parameter.
-- Example call:
--
-- SELECT a.partition_name,
-- part_hv_to_date(a.table_owner, a.table_name, a.partition_name) as
high_value
-- FROM all_tab_partitions a;
--
-- Does no error handling.
-- --------------------------------------------------------------------------
---------
l_high_value varchar2(32767);
l_date date;
begin
select high_value
into l_high_value
from DBA_TAB_PARTITIONS
where table_owner = p_table_owner
and table_name = p_table_name
and partition_name = p_partition_name;

execute immediate 'select ' || l_high_value || ' from dual' into l_date;
return l_date;
end;

-- Типовая операция удаления структур (ежемесячного файл-tablespace и


ежесуточных секций в нём) в IOT старше заданного размера архива
PROCEDURE PRC_DEL_IOT_STR(p_table_owner in
DBA_TAB_PARTITIONS.table_owner%Type,
p_table_name in
DBA_TAB_PARTITIONS.table_name%Type,
p_tablespace_name in
DBA_TAB_PARTITIONS.tablespace_name%Type,
p_file_name in
DBA_DATA_FILES.file_name%Type) is
cnt integer;
v_sql varchar2(1000);

cursor cur_p(v_ts in DBA_TAB_PARTITIONS.tablespace_name%Type) is


select distinct partition_name
from DBA_IND_PARTITIONS -- т.к. DBA_TAB_PARTITIONS.tablespace_name =
null
where tablespace_name = v_ts;
BEGIN
-- Удаляем все секции заданного tablespace старше заданного размера
архива
for j in cur_p(p_tablespace_name) loop
if FN_PART_HV_TO_DATE(p_table_owner, p_table_name, j.partition_name) <
add_months(sysdate, -const_month_cnt) then
v_sql := 'alter table ' || p_table_owner || '.' || p_table_name || '
drop partition ' || j.partition_name;
PRC_Trace_Log(v_Message => 'PCK_IOT.PRC_DEL_IOT_STR: sql='
|| v_sql
|| '.'
|| p_tablespace_name);
execute immediate v_sql;
end if;
end loop;
select count(*)
into cnt
from DBA_IND_PARTITIONS
where tablespace_name = p_tablespace_name;
if cnt = 0 then -- в tablespaсe отсутствуют секции
-- Уменьшаем размер файла tablespaсe
v_sql := 'alter database datafile ''' || p_file_name || ''' resize 2M';
PRC_Trace_Log(v_Message => 'PCK_IOT.PRC_DEL_IOT_STR: sql='
|| v_sql);
execute immediate v_sql;

-- Удаляем tablespaсe вместе с файлом (в Windows файл может не


удалиться из-за блокировки службой)
v_sql := 'drop tablespace ' || p_tablespace_name || ' including
contents and datafiles';
PRC_Trace_Log(v_Message => 'PCK_IOT.PRC_DEL_IOT_STR: sql='
|| v_sql);
execute immediate v_sql;
/*
begin
-- Удаляем файл (в Windows может не удалиться из-за блокировки службой)
PRC_Trace_Log(v_Message => 'PCK_IOT.PRC_DEL_IOT_STR: utl_file.fremove='
|| SUBSTR(p_file_name, INSTR(p_file_name,'\', -
1, 1) + 1, LENGTH(p_file_name) - INSTR(p_file_name,'\', -1, 1)));
utl_file.fremove('ORACLE_DATA_FILES', SUBSTR(p_file_name,
INSTR(p_file_name,'\', -1, 1) + 1, LENGTH(p_file_name) -
INSTR(p_file_name,'\', -1, 1)));

exception
when others then
PRC_Trace_Log(v_Message => 'PCK_IOT.PRC_DEL_IOT_STR: '
|| DBMS_UTILITY.FORMAT_ERROR_STACK);
end;
*/
end if;

EXCEPTION
WHEN OTHERS THEN
PRC_Trace_Log(v_Message => 'PCK_IOT.PRC_DEL_IOT_STR: '
|| DBMS_UTILITY.FORMAT_ERROR_STACK);
END;

-- Типовая операция создания структур (ежемесячного файл-tablespace и


ежесуточных секций в нём) в IOT на 1 следующий месяц вперед
PROCEDURE PRC_NEW_IOT_STR(p_table_owner in
DBA_TAB_PARTITIONS.table_owner%Type,
p_table_name in
DBA_TAB_PARTITIONS.table_name%Type,
p_tablespace_name in
DBA_TAB_PARTITIONS.tablespace_name%Type) is
cnt integer;
v_tablespace_name varchar2(28);
v_sql varchar2(1000);
BEGIN
select count(*)
into cnt
from DBA_DATA_FILES
where tablespace_name like2 p_tablespace_name || '%'
and to_date(substr(tablespace_name, -7, 7), 'mm_yyyy') >
trunc(sysdate, 'MM'); -- на 1 месяц вперед (1 месяц = 1 файл = 1 tablespace)
if cnt = 0 then -- Отсутствует tablespace на следующий месяц
v_tablespace_name := p_tablespace_name || to_char(add_months(sysdate,
1),'mm_yyyy');
v_sql := 'create smallfile tablespace '
|| v_tablespace_name
|| ' datafile size 100M autoextend on next 128M maxsize
unlimited logging extent management local segment space management auto';
begin
PRC_Trace_Log(v_Message => 'PCK_IOT.PRC_NEW_IOT_STR: sql='
|| v_sql);
-- Создать tablespace на новый месяц
execute immediate v_sql;
exception
WHEN OTHERS THEN
PRC_Trace_Log(v_Message => 'PCK_IOT.PRC_NEW_IOT_STR: '
|| DBMS_UTILITY.FORMAT_ERROR_STACK);
end;

-- Дать разрешение пользователю на новый tablespace


v_sql := 'alter user ' || p_table_owner || ' quota unlimited on ' ||
v_tablespace_name;
PRC_Trace_Log(v_Message => 'PCK_IOT.PRC_NEW_IOT_STR: sql='
|| v_sql);
execute immediate v_sql;

-- Создать секцию на каждые новые сутки в новом tablespace


for i in 1..extract(day from last_day(add_months(trunc(sysdate, 'MM'),
1))) loop
v_sql := 'alter table ' || p_table_owner || '.' || p_table_name || '
add partition values less than (TO_DATE('''
|| to_char(add_months(trunc(sysdate, 'MM'),1)+i,'dd.mm.yyyy')
|| ''',''DD.MM.YYYY'')) tablespace '
|| v_tablespace_name
|| ' COMPRESS';
PRC_Trace_Log(v_Message => 'PCK_IOT.PRC_NEW_IOT_STR: sql='
|| v_sql);
execute immediate v_sql;
end loop;
end if;

EXCEPTION
WHEN OTHERS THEN
PRC_Trace_Log(v_Message => 'PCK_IOT.PRC_NEW_IOT_STR: '
|| DBMS_UTILITY.FORMAT_ERROR_STACK);
END;

-- Проверка IOT
PROCEDURE PRC_CHK_IOT(p_table_owner in
DBA_TAB_PARTITIONS.table_owner%Type,
p_table_name in
DBA_TAB_PARTITIONS.table_name%Type,
p_tablespace_name in
DBA_TAB_PARTITIONS.tablespace_name%Type) is

cursor cur_ts(v_ts in DBA_TAB_PARTITIONS.tablespace_name%Type) is


select tablespace_name,
file_name
from DBA_DATA_FILES
where tablespace_name like2 v_ts || '%'
and to_date(substr(tablespace_name, -7, 7), 'mm_yyyy') <
add_months(sysdate, -const_month_cnt)
order by to_date(substr(tablespace_name, -7, 7), 'mm_yyyy'); -- Типовое
наименование ежемесячных tablespaces в формате <tablespace name>_mm_yyyy
BEGIN
for i in cur_ts(p_tablespace_name) loop
-- Удаление структур (ежемесячного файл-tablespace и ежесуточных секций
в нём) в IOT старше заданного размера архива
PRC_DEL_IOT_STR(p_table_owner => p_table_owner,
p_table_name => p_table_name,
p_tablespace_name => i.tablespace_name,
p_file_name => i.file_name);
end loop;

-- Создание структур (ежемесячного файл-tablespace и ежесуточных секций в


нём) в IOT на 1 следующий месяц вперед
PRC_NEW_IOT_STR(p_table_owner => p_table_owner,
p_table_name => p_table_name,
p_tablespace_name => p_tablespace_name);
END;

-- Ручной перебор всех IOT для проверки


PROCEDURE PRC_CHK_ALL_IOT is
begin
delete HIST_LOGS
where dt < sysdate - 365;
commit;
PRC_CHK_IOT(p_table_owner => 'APP2_L2',
p_table_name => 'LOGGING',
p_tablespace_name => 'TS_LOG_');
end;

END;

Скрипт создания плановой задачи JOB_TABLESPACE:

begin
sys.dbms_scheduler.create_job(job_name =>
'IOT_MANAGER.JOB_TABLESPACE',
job_type => 'STORED_PROCEDURE',
job_action =>
'PCK_IOT.PRC_CHK_ALL_IOT',
start_date => to_date('01-01-2020
00:00:00', 'dd-mm-yyyy hh24:mi:ss'),
repeat_interval =>
'Freq=Daily;Interval=1',
end_date => to_date(null),
job_class => 'DEFAULT_JOB_CLASS',
enabled => true,
auto_drop => false,
comments => '');
end;