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

Hvordan man implementerer multidimensionelle sekvenser

Den eneste måde at gøre dette på er med en kodekontroltabel ...

create table code_control
    (year number(4,0) not null
     , type varchar2(1) not null
     , last_number number(38,0) default 1 not null
     , primary key (year,type)
    )
organization index
/   

... som vedligeholdes sådan ...

create or replace function get_next_number
    (p_year in number, p_type in varchar2)
    return number
is
    pragma autonomous_transaction;
    cursor cur_cc is
        select last_number + 1
        from code_control cc
        where cc.year= p_year
        and cc.type = p_type
        for update of last_number;
    next_number number;
begin
    open cur_cc;
    fetch cur_cc into next_number;
    if cur_cc%found then
        update code_control
        set last_number = next_number
        where current of cur_cc;
    else
        insert into code_control (year,type)
        values (p_year, p_type)
        returning last_number into next_number;
    end if;    
    commit;
    return next_number;
end;
/

Det vigtige er VÆLG ... TIL OPDATERING. Pessimistisk låsning garanterer unikhed i et flerbrugermiljø. PRAGMA'en sikrer, at opretholdelse af code_control forurener ikke den bredere transaktion. Det giver os mulighed for at kalde funktionen i en trigger uden deadlocks.

Her er en tabel med en nøgle som din:

create table t42
     (year number(4,0) not null
     , type varchar2(1) not null
     , id number(38,0) 
     , primary key (year,type, id)
)
/
create or replace trigger t42_trg
    before insert on t42 for each row
begin
    :new.id := get_next_number(:new.year, :new.type);
end;
/

Der er ikke noget i ærmet, før jeg udfylder t42 :

SQL> select * from code_control;

no rows selected

SQL> select * from t42;

no rows selected

SQL> insert into t42 (year, type) values (2016, 'A');

1 row created.

SQL> insert into t42 (year, type) values (2016, 'A');

1 row created.

SQL> insert into t42 (year, type) values (2016, 'A');

1 row created.

SQL> insert into t42 (year, type) values (2016, 'B');

1 row created.

SQL> insert into t42 (year, type) values (2016, 'A');

1 row created.

SQL> insert into t42 (year, type) values (2017, 'A');

1 row created.

SQL> select * from t42;

      YEAR T         ID
---------- - ----------
      2016 A          1
      2016 A          2
      2016 A          3
      2016 A          4
      2016 B          1
      2017 A          1

6 rows selected.

SQL> select * from code_control;

      YEAR T LAST_NUMBER
---------- - -----------
      2016 A           4
      2016 B           1
      2017 A           1

SQL> 

Så den åbenlyse indvending mod denne implementering er skalerbarhed. Indsættelsestransaktioner serialiseres på code_control bord. Det er helt rigtigt. Låsen holdes dog i kortest mulig tid, så dette burde ikke være et problem, selvom t42 tabellen udfyldes mange gange i sekundet.

Men hvis bordet udsættes for et massivt antal samtidige indsatser, kan låsningen blive et problem. Det er afgørende, at bordet har tilstrækkelige Interested Transaction slots (INITRANS, MAXTRANS) til at klare samtidige krav. Men meget travle systemer kan have brug for en smartere implementering (måske generere ID'erne i batches); ellers opgive den sammensatte nøgle til fordel for en sekvens (fordi sekvenser skaleres i flerbrugermiljøer).




  1. MySQL-fejlkode:1064. Du har en fejl i din SQL-syntaks

  2. Sådan finder du intervalværdi fra databasen

  3. hvordan man viser hele variablen med plads i tekstboksen i php

  4. Postgres:Sorter efter strengkolonne med kendte værdier