Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Precisa redefinir o valor da sequência no Oracle

Motivos pelos quais você não deve redefinir o valor se estiver sendo usado:


O que acontece se você tiver 20 registros e excluir os registros de 5 a 10? Você tem uma lacuna no meio que redefinir a sequência não resolverá. As sequências nunca gerar uma sequência de números sem lacunas, um perfeito 1, 2 .. n .

Se você chamar .nextval e não use o valor que se foi . Você vai largar e recriar a sequência? Se você iniciar uma inserção e cancelá-la e o Oracle reverter o que você fez, esses valores sumiram . Se você definir nocache então você terá menos lacunas, mas ao custo de um impacto no desempenho; Vale a pena?

Seu cache deve ser definido para o número de inserções que você espera fazer a qualquer momento em todas as sessões para evitar quaisquer problemas de desempenho. As sequências são projetadas para fornecer uma maneira muito rápida e escalável de criar uma chave substituta sem travas etc. não para gerar novamente o conjunto de inteiros positivos.

No final do dia, não deveria importar nem um pouco. Se você está contando com uma sequência ininterrupta como a chave da sua tabela, então você tem um problema com seus dados em vez de sequências.

Respondendo à pergunta:


Para realmente responder sua pergunta, você precisaria:
  1. Primeiro, descubra qual é o valor máximo de id (sequência) em sua tabela.
  2. Em seguida, solte e recrie a sequência.

Encontrar o valor máximo significa que você precisa recriar a sequência dinamicamente ao custo de outro impacto no desempenho.

Se você tentar inserir algo em sua tabela enquanto isso está acontecendo, ele falhará e poderá invalidar quaisquer gatilhos ou outros objetos que usem a sequência:
declare

   l_max_value number;

begin

   select max(id)
     into l_max_value
     from my_table;

   execute immediate 'drop sequence my_sequence_name';

   -- nocache is not recommended if you are inserting more than
   -- one row at a time, or inserting with any speed at all.
   execute immediate 'create sequence my_sequence_name
                           start with ' || l_max_value
                      || ' increment by 1
                           nomaxvalue
                           nocycle
                           nocache';

end;
/

Como eu disse, isso não é recomendado e você deve simplesmente ignorar quaisquer lacunas.

Atualização - também conhecida como Uma resposta melhor, graças a Jeffrey Kemp:


Ao contrário da recomendação da documentação, há, como Jeffrey Kemp sugeriu nos comentários, uma maneira de fazer isso sem descartando e recriando a sequência.

A saber, por:
  1. Como calcular a diferença entre o id máximo na sua tabela e o valor atual da sequência.
  2. Alterando a sequência para incrementar por este número negativo
  3. Alterando a sequência para incrementar em 1 novamente.

Os benefícios disso são que o objeto ainda existe e gatilhos, concessões etc. ainda são mantidos. A desvantagem, a meu ver, é que, se outra sessão aumentar esse número negativo ao mesmo tempo que a sua, você pode voltar muito longe.

Aqui está uma demonstração:

Configure o teste:

SQL> create sequence test_seq
  2   start with 1
  3   increment by 1
  4   nomaxvalue
  5   nocycle
  6   nocache;

Sequence created.

SQL>
SQL> create table tmp_test ( id number(16) );

Table created.

SQL>
SQL> declare
  2     l_nextval number;
  3  begin
  4
  5    for i in 1 .. 20 loop
  6       insert into tmp_test values ( test_seq.nextval );
  7    end loop;
  8
  9  end;
 10  /

PL/SQL procedure successfully completed.

SQL>
SQL> select test_seq.currval from dual;

   CURRVAL
----------
        20

SQL>
SQL> delete from tmp_test where id > 15;

5 rows deleted.

SQL> commit;

Commit complete.

Reverta a sequência

SQL>
SQL> declare
  2
  3     l_max_id number;
  4     l_max_seq number;
  5
  6  begin
  7
  8     -- Get the maximum ID
  9     select max(id) into l_max_id
 10       from tmp_test;
 11
 12     -- Get the current sequence value;
 13     select test_seq.currval into l_max_seq
 14       from dual;
 15
 16     -- Alter the sequence to increment by the difference ( -5 in this case )
.
 17     execute immediate 'alter sequence test_seq
 18                          increment by ' || ( l_max_id - l_max_seq );
 19
 20     -- 'increment' by -5
 21     select test_seq.nextval into l_max_seq
 22       from dual;
 23
 24     -- Change the sequence back to normal
 25     execute immediate 'alter sequence test_seq
 26                          increment by 1';
 27
 28  end;
 29  /

PL/SQL procedure successfully completed.

SQL>
SQL> select test_seq.currval from dual;

   CURRVAL
----------
        15

SQL>