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...FORUPDATEです。ペシミスティックロックは、マルチユーザー環境での一意性を保証します。 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であっても、これは問題にはなりません。 テーブルは1秒間に何度も入力されます。

    ただし、テーブルが大量の同時挿入にさらされると、ロックが問題になる可能性があります。同時要求に対処するために、テーブルに十分な関心のあるトランザクションスロット(INITRANS、MAXTRANS)があることが重要です。ただし、非常にビジーなシステムでは、よりスマートな実装が必要になる場合があります(IDをバッチで生成する可能性があります)。それ以外の場合は、シーケンスを優先して複合キーを破棄します(シーケンスはマルチユーザー環境でスケーリングするため)。




    1. データベースのレコードを自動更新するにはどうすればよいですか?

    2. SQLAlchemyの複雑な外部キー制約

    3. MATCH()AGAINST()を使用した文字列と数値のMySQL検索

    4. MySQL:テーブルを追加の列を持つ別のテーブルにコピーします