S-JIS[2023-10-09/2024-02-24]

Tsurugi insert

TsurugiSQLのinsertのメモ。


概要

TsurugiのSQLでテーブルにデータを追加するのがinsert文。

Tsurugi 1.0.0-BETA1では、select-insert(insert into テーブル select 〜)は未実装。


通常のinsert文では、同一プライマリキーのデータが既に存在していると、一意制約違反(UNIQUE_CONSTANT_VIOLATION_EXCEPTION)のエラーになる。[2024-02-24]
このエラーが発生すると、そのトランザクションはもう使えない。(この状態でSQLやcommitを実行するとINACTIVE_TRANSACTION_EXCEPTIONが発生する。こうなったら、rollbackでトランザクションを終了させる)


insertの例

insert into test (foo, bar, zzz) values(1, 123, 'abc');
insert into test values(2, 456, 'def');

指定できるリテラル(値)


insert or replaceの例

insert or replaceは、テーブルにデータが無い場合は追加し、有る場合は更新する。(データの有無はプライマリキーで判断する)

insert or replace into test values(1, 111, 'overwrite');

なお、insert or replaceのエイリアスとして、update or insertとも書ける。[2023-10-22]


単なるinsertの場合、書き込み前に、テーブル内に既にデータが存在しているかどうかチェックする。(存在していたら一意制約違反になる)[2023-12-15]

insert or replaceの場合、既存データの有無に関わらず、問答無用でデータを書き込む。
このため、insert or replaceは(存在チェックを行わない分、)insertよりも高速。
また、同じ理由で、insert or replaceでは一意制約違反は発生しない。

この挙動は、Tsurugiの内部の仕組みを知っていると理解しやすい。[2024-02-24]

Tsurugiでは「トランザクション機能を持つKVS」という構造(Masstree)でデータを保持している。
これは例えるならJavaのTreeMap(キー順に並んでいるMap)のようなもの。
insertとinsert or replaceは、以下のような処理を行っている。

JavaのTreeMapでの例え
insert insert or replace
if (map.containsKey(key)) {
  throw new 一意制約違反();
}
map.put(key, record);
map.put(key, record);

実際、Tsurugi内部ではSQLをKVSの処理に変換して実行している。
insertはgetとputを行い、insert or replaceはputのみを行っている。


insertとinsert or replaceの違いは、トランザクションの競合(シリアライザブルのチェック)にも現れてくる。[2024-02-24]

Tsurugiのトランザクションの用語では、KVSのgetのことをread(略してr)、putのことをwrite(略してw)と呼ぶらしい。
それを使って、insertはreadしてからwriteするのでrw、insert or replaceはwriteのみなのでwと表記する。
updateやdeleteも処理対象を読んでからそれに対して変更する(書き込む)のでrwである。

OCCでreadを行った場合、コミット時に「読んだデータが他トランザクションによって変更(およびコミット)されていないかどうか」 のチェックが入り、変更されていた場合はシリアライゼーションエラー(CC_EXCEPTION)になる。
したがって、rwであるinsert・update・deleteはreadに関するシリアライゼーションエラーになる可能性がある。
しかしwであるinsert or replaceはreadしていないので、readに関するシリアライゼーションエラーになることは無い。

例えば、2つのトランザクションT1とT2が同じデータを更新するとき、以下のような違いが出る。
create table tb (pk int primary key, value int);で、pk=1のデータが入っているものとする)

  T1 T2
rw(update) w(insert or replace)
1 begin; -- OCC begin; -- OCC  
2 update tb set value = 11 where pk = 1; insert or replace into tb values(1, 11);  
3     begin; -- OCC
4     update tb set value = 22;
5     commit; →OK(value = 22)
6 commit;CC_EXCEPTION commit; →OK(value = 11)  

insert if not existsの例

insert if not existsは、テーブルにデータが存在しない場合だけ追加する。(データの有無はプライマリキーで判断する)
データが有る場合は何もしない。(単なるinsertだと一意制約違反が発生するが、if not existsの場合はPKの一意制約違反は発生しない)

insert if not exists into test values(3, 456, 'not exists');

Tsurugi 1.0.0-BETA2(tgsql 1.1.0やIceaxe 1.1.0)以降では、実際にインサートした件数が返る。[2024-02-24]
データが無かった場合は(インサートして)1が返るが、データが既に存在していた場合は(何もせず)0が返る。


Tsurugi SQLへ戻る / Tsurugiへ戻る / 技術メモへ戻る
メールの送信先:ひしだま