sql >> Databasteknik >  >> RDS >> Oracle

Behöver återställa värdet på sekvensen i Oracle

Skäl till varför du inte bör återställa värdet om det används:

Vad händer om du har 20 poster och raderar poster 5-10? Du har en lucka i mitten som inte löser att återställa sekvensen. Sekvenser kommer aldrig generera en mellanrumsfri nummersekvens, en perfekt 1, 2 .. n .

Om du ringer .nextval och använd inte värdet det är borta . Kommer du att släppa och återskapa sekvensen? Om du startar en infogning och avbryter den och Oracle återställer det du har gjort är dessa värden borta . Om du ställer in nocache då kommer du att ha mindre luckor men till en kostnad av en träff till prestanda; är det värt det?

Ditt cacheminne bör ställas in på antalet infogningar du förväntar dig att göra vid en viss tidpunkt över alla sessioner för att undvika prestandaproblem. Sekvenser är designade för att ge ett mycket snabbt, skalbart sätt att skapa en surrogatnyckel utan några lås etc. inte för att återgenerera uppsättningen positiva heltal.

I slutet av dagen borde det inte spela någon roll. Om du förlitar dig på en obruten sekvens som nyckeln i din tabell har du problem med dina data snarare än sekvenser.

Svar på frågan:

För att faktiskt svara på din fråga skulle du behöva:

  1. Ta först reda på vad det maximala värdet för id (sekvens) i tabellen är.
  2. Släpp sedan och återskapa sekvensen.

Att hitta det maximala värdet innebär att du måste återskapa sekvensen dynamiskt till priset av ytterligare en prestationsträff.

Om du försöker infoga något i din tabell medan detta händer kommer det att misslyckas och kan ogiltigförklara alla triggers eller andra objekt som använder sekvensen:

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

Som jag säger rekommenderas detta inte och du bör bara ignorera eventuella luckor.

Uppdatering - aka A Better Answer Tack vare Jeffrey Kemp:

I motsats till dokumentationens rekommendation finns det, som Jeffrey Kemp föreslog i kommentarerna, ett sätt att göra detta utan släppa och återskapa sekvensen.

Nämligen av:

  1. Tränar ut skillnaden mellan det maximala id i din tabell och det aktuella värdet för sekvensen.
  2. Ändra sekvensen för att öka med detta negativa tal
  3. Ändra sekvensen för att öka med 1 igen.

Fördelarna med detta är att objektet fortfarande existerar så och triggers, bidrag etc fortfarande bibehålls. Nackdelen, som jag ser det, är att om en annan session ökar med detta negativa tal samtidigt som din kan du gå tillbaka för långt.

Här är en demonstration:

Ställ in testet:

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.

Återställ sekvensen

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>


  1. Får NoClassDefFoundError när jag försöker använda Proguard och SQLcipher i Android

  2. Hur DIV fungerar i MariaDB

  3. Varför använda join istället för var i MySQL-frågor?

  4. Välj COUNT(*) med DISTINCT