S-JIS[2023-10-09/2024-02-24]
|
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 into test (foo, bar, zzz) values(1, 123, 'abc');
insert into test values(2, 456, 'def');
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は、以下のような処理を行っている。
insert | insert or replace |
---|---|
if (map.containsKey(key)) { |
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の場合は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が返る。