2021年3月13日土曜日

クイックSQLのデフォルト指定

Conner McDonaldさんのツイートで、彼が過去に書いた記事の話をしていました。

彼の記事では、以下を推奨しています。

列のデフォルト値の指定にトリガーを使用すると遅くなるので、そのかわりにdefault on nullを使用すべき。

クイックSQLで生成されるSQLを確認してみました。最新版のOracle APEXにバンドルされているクイックSQLは何故か、11g向けのDDLは生成しなくなったので(DBのバージョンに11gを選択しても)、LiveSQLを使って確認します。

確認に使うクイックSQLのモデルは以下です。主キーとして列IDが生成され、それ以外に列MY_DATEを定義しています。この列のデフォルト値はSYSDATEです。

test
    my_date date /default sysdate

最初に11g向けのDDLを生成します。

# pk: seq
# db: 11g
test
    my_date date /default sysdate

生成されたDDLは以下です。

-- create tables
create table test (
    id                             number not null constraint test_id_pk primary key,
    my_date                        date default SYSDATE
)
;


-- triggers
create sequence test_seq;

create or replace trigger test_biu
    before insert or update 
    on test
    for each row
begin
    if :new.id is null then
        :new.id := test_seq.nextval;
    end if;
end test_biu;
/

Conner McDonaldさんの記事では、SELECTの結果を一括して表にロードするINSERT SELECT文の実行により1千万行をトリガーの付いた表にロードすると、トリガーが有効なときは6分37秒かかり、トリガーが無効であれば、4秒弱で終了したという例が示されています。

Oracle Database 11gであれば仕方がないですが、12c以降であればidentityを使いましょう。クイックSQLでDBを12c(またはその上位バージョン)を指定するとデフォルトで主キーの設定にID列が選択されます。

# db: 12c
test
    my_date date /default sysdate

生成されるDDLは以下になります。

-- create tables
create table test (
    id                             number generated by default on null as identity  
                                   constraint test_id_pk primary key,
    my_date                        date default SYSDATE
)
;

トリガーの定義は無くなりました。

主キーとなる列IDについてはdefault on nullの定義ですが、列MY_DATEのデフォルト設定は、default on nullではなく、単にdefaultです。

動作を確認します。以下のSQL文を実行します。

delete from test;
insert into test(id) values(1);
insert into test(my_date) values(null);
select * from test;

結果は以下になります。値の指定がないときはデフォルト値のSYSDATEが設定されますが、明示的にNULLが指定されているときはNULLになります。

IDMY_DATE
113-MAR-21
8 -

列MY_DATEの定義をDEFAULT ON NULLとなるように変更します。

alter table test modify (my_date default on null sysdate);

同じSQL文を実行します。結果は以下になります。


Result Set 7

IDMY_DATE
113-MAR-21
913-MAR-21

値としてnullを指定した場合でも、デフォルト値が適用されています。

主キーはさておき、クイックSQLの列ディレクティブで/defaultを指定した場合は、生成されたDDLを確認し、望んでいる動作がdefault on nullであれば、レビュー時にDDLを更新しましょう。

本記事は以上です。

Oracle APEXのアプリケーション開発の一助になれば幸いです。