Oracle
 sql >> Database >  >> RDS >> Oracle

Necessità di reimpostare il valore della sequenza in Oracle

Motivi per cui non dovresti reimpostare il valore se viene utilizzato:

Cosa succede se hai 20 record ed elimini i record 5-10? Hai uno spazio vuoto nel mezzo che il ripristino della sequenza non risolverà. Le sequenze mai generare una sequenza di numeri priva di gap, un perfetto 1, 2 .. n .

Se chiami .nextval e non utilizzare il valore andato . Hai intenzione di rilasciare e ricreare la sequenza? Se avvii un inserimento e lo annulli e Oracle ripristina ciò che hai fatto, quei valori sono scomparsi . Se imposti nocache quindi avrai meno lacune ma a costo di un colpo in termini di prestazioni; ne vale la pena?

La tua cache dovrebbe essere impostata sul numero di inserimenti che prevedi di fare in qualsiasi momento in tutte le sessioni per evitare problemi di prestazioni. Le sequenze sono progettate per fornire un modo molto rapido e scalabile per creare una chiave surrogata senza lucchetti, ecc non per rigenerare l'insieme degli interi positivi.

Alla fine della giornata non dovrebbe importare minimamente. Se fai affidamento su una sequenza ininterrotta come chiave della tua tabella, allora hai un problema con i tuoi dati piuttosto che con le sequenze.

Risposta alla domanda:

Per rispondere effettivamente alla tua domanda dovresti:

  1. In primo luogo, scopri qual è il valore massimo di id (sequenza) nella tua tabella.
  2. Quindi rilascia e ricrea la sequenza.

Trovare il valore massimo significa che dovresti ricreare la sequenza in modo dinamico al costo di un altro colpo alle prestazioni.

Se provi a inserire qualcosa nella tua tabella mentre sta accadendo, fallirà e potrebbe invalidare tutti i trigger o altri oggetti che usano la sequenza:

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;
/

Come ho detto, questo non è raccomandato e dovresti semplicemente ignorare eventuali lacune.

Aggiorna - alias Una risposta migliore grazie a Jeffrey Kemp:

Contrariamente alla raccomandazione della documentazione, esiste, come suggerito da Jeffrey Kemp nei commenti, un modo per farlo senza rilasciare e ricreare la sequenza.

Vale a dire, da:

  1. Calcolare la differenza tra l'id massimo nella tabella e il valore corrente della sequenza.
  2. Alterare la sequenza per incrementare di questo numero negativo
  3. Alterare la sequenza per incrementare nuovamente di 1.

I vantaggi di ciò sono che l'oggetto esiste ancora così e vengono mantenuti trigger, sovvenzioni ecc. Lo svantaggio, a mio avviso, è che se un'altra sessione aumenta di questo numero negativo contemporaneamente alla tua, puoi tornare troppo indietro.

Ecco una dimostrazione:

Imposta il test:

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.

Ripristina la sequenza

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>