Oracle
 sql >> база данни >  >> RDS >> Oracle

Как да реализираме многоизмерни последователности

Единственият начин да направите това е с таблица за контрол на код ...

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
/   

... който се поддържа така ...

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

Важното е SELECT ... FOR UPDATE. Песимистичното заключване гарантира уникалност в среда с множество потребители. PRAGMA гарантира, че поддържането на code_control не замърсява по-широката сделка. Това ни позволява да извикаме функцията в тригер без блокиране.

Ето таблица с ключ като вашия:

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

Нямам нищо в ръкава си, преди да попълня 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> 

Така че очевидното възражение срещу тази реализация е мащабируемостта. Транзакциите за вмъкване се сериализират в code_control маса. Това е абсолютно вярно. Заключването обаче се задържа за възможно най-кратко време, така че това не би трябвало да е проблем, дори ако t42 таблицата се попълва много пъти в секунда.

Въпреки това, ако таблицата е подложена на огромен брой едновременни вмъквания, заключването може да се превърне в проблем. От решаващо значение е таблицата да има достатъчно слотове за заинтересовани транзакции (INITRANS, MAXTRANS), за да се справи с едновременните изисквания. Но много натоварените системи може да се нуждаят от по-интелигентно внедряване (може би генериране на идентификатори на партиди); в противен случай изоставете съставния ключ в полза на последователност (защото последователностите се мащабират в среди с много потребители).




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. WHERE CURRENT OF в PL/SQL

  2. Как да избера подниз в oracle?

  3. Java Date.toString в TO_DATE на Oracle

  4. Как да получите достъп до системните таблици на Oracle от вътрешността на PL/SQL функция или процедура?

  5. Намерете диапазони от поредица от числа в SQL/Oracle