もちろん、優劣や速度の面で議論するのは的外れです。
Case by Caseです。と結論つけると、何も主張していないことになりますね。
私の基準は、該当レコードがリーフ行(自分行を親とする子データ)である時は、Updateにします。
自分の行が親(鏡行)になっていて、明細が付く時は、Delete/Insertで作るようにしています。
理由:
修正前と修正後で明細行の行数が増減するとき、 Delete/Insertでないと、処理が煩雑になる
例)
修正前
明細NO 品名 個数
明細1: 01 aaa 10
明細2: 02 bbb 20
明細3: 03 ccc 30
この伝票で、 明細2が抹消になり, 明細3の個数が 22 に変わり, 1行追加( ddd 40個) があった。
明細1を最後に持って行きたい。
業務仕様で、明細NOは1基準の通番にしないといけない。
(このシーンは誇張ではなく、現場では起こりうる要求だったりします。)
この場合、明細2を消して 、明細3を変更して、明細4を追加し、明細NOを振り直す。 よりも、一旦、明細を削除して、新規Insertした方がシンプルになります。
修正後
明細NO 品名 個数
明細3: 01 ccc 22
明細4: 02 ddd 40
明細1: 03 aaa 10
業務面から見ると、どちらでも結果は同じなので、安定して作れるほうが良いと思います。
連番の付け方が問題になることがあります。
SQL ServerのIdentity項目やOracleのシーケンスは便利なんですが、トランザクションとの相性が悪く、ロールバックが起こると欠番が生じます。
いずれにしても、表示連番は、自力で管理する必要があります。
昔は、Delete/Insertで生じるData領域の抜け穴の処理問題がおおきく、「駄目だ/嫌だ」と主張する人もいましたね。
この主張は、当時から納得できませんでした。トリガーをみれば、
SQL Serverの更新トリガーでは変更前後は Delete/Insertに格納されていますし、 Oracleでも new/oldに格納されています。
RDBの内部実装上は、delete/insert的な仕組みで処理されているのでしょうね。
となると、アプリでどちらが良いかの議論は陰が薄れると思うのです。(下段補足)
今日のように、大容量HDDの時代では、定期的に全体のコンプレスすることもあり、個別の穴を意識することも少なくなりました。
(*) 少し後ろめたさは感じるのは、Byte単位で短いプログラムを作ったり、データ無効化による領域穴が、リソース的に大きな問題になっていた時代のトラウマでしょうか。
メモリアロケーションを自前でしてた当時、サイズとアロック順を意識しましたが、GCに依存する環境では、穴を意識することはないですね。
それと同様に、RDBでも、穴を意識しない時代になったのでしょうか。
(*)上記の例は 比較するために想定した例です。
実務で上記の更新操作は疑問です。伝票は、更新/削除するのは駄目で、赤黒処理するのが基本です。その面では、常に Insertになります。
更新でも削除でも、変更履歴を残すのは基本なので、変更履歴を追跡して、過去に戻って復元可能だからOKだとの意見もありますが、復元する仕組みは面倒そうですね。
「実装のしやすさで判断すれば良い」というのが、私の思いです。
鏡と明細の二次元ならこれで良いのですが、3次元以上の階層構造のテーブルになると、何が適切なのか判りません。
そのときは、Classのシリアライズ機能に適応して欲しいと願うのです。(Sql ServerのXML項目で可能か、試行してみて、挫折したのは内緒です。)
(PS). RDB内部で Delete/Insertしているという意味ではなく、 変更前後のデータほ保持しているのと、 rolleback/Comit用に多くの領域を確保しているので、行単位のdelete/Insert とupdateの領域効率を厳密に追求するのはどうなのなかぁ..という意味です。