![見出し画像](https://assets.st-note.com/production/uploads/images/136806744/rectangle_large_type_2_4aa09053c54ca8d60c2eee54f993eb9e.png?width=1200)
QAが知っていて損はないDBの「削除」について
DBのCRUD(Create-Read-Update-Delete)について広く解説している記事は多々ありますが、私はこのうち開発する上で最も危険性が高く、それゆえに知っておくといいのはDeleteだと考えています。その理由なども含めて今回記事にしてみたいと思います。
少しでも参考になれば幸いです。
DBの「削除」が危険な理由
今回主に触れるのは厳密にはDBのレコード(データベースの中の行)の削除ですが、それ以外でも、
カラム(データベースの列)の削除
テーブルの削除
データベースの削除
などなど、データベース関係の削除にまつわる変更には基本的に危険が付きまといます。なぜかというと、「削除したレコード/カラム/テーブル/データベースを参照する処理」が一行でもあると、その行は確実に参照エラーを起こすためです。
レコードの削除はユースケースとして想定されエラーハンドリングされることが多いのでいいですが、カラム、テーブル、データベースの削除に関しては参照している処理が削除されたことを前提とする関係上アプリケーション内でエラーハンドリングを行わない場合もあり、発生した時点でアプリケーションが丸ごと落ちることもありえます。めっちゃ怖くないですか?
レコードの削除について知っておくといい単語
前置きが長くなりましたが、レコードの削除についてです。
ここではソフトウェアエンジニアの方と会話をする上でも役立つ単語をピックアップしてみたいと思います。
物理削除と論理削除
「ぶっさく」「ろんさく」と呼ぶこともあります。
テーブルをGoogleスプレッドシートのシート、レコードをシートの中の一行のデータと考えると、
「行を削除」で実際に行を消してしまうこと:物理削除
「この処理は取り消せません」などアラートが出る場合は大抵これ
削除を示すカラムをレコードの中に持っておき、フラグを立てること:論理削除
裏側ではデータを保持しているため、やろうと思えばデータを復元できる
設計書に「isDeleted」や「deletedAt」といったカラムが定義されていればこっち
となります。
そう聞くと「何かあった時のことを考えると論理削除の方が良くない?」と少なくとも私は考えたことがあるのですが、無尽蔵にレコードが増え続けて容量を圧迫すること、カラムにユニーク制約(同じテーブルの同じカラムの中で同一の値を持つことができない制約のこと。ユーザーIDをイメージしてもらえるといいと思います)を設定していた場合に引っかかってしまうことがあるなど、一概に論理削除が良いとは言えません。
外部キー制約(CASCADE, RESTRICT, SET NULL)
これはテーブル同士の結合を行う際に関係する設定です。
例として、架空のSNSを挙げます。まず最初にユーザー登録を行い、その後投稿を行ったとします。その投稿にはユーザー情報が紐づいています。
このとき、ユーザーを削除したらどうなるでしょうか?
実はこの場合起こりうる状況には4パターンあります。
ユーザーに紐づく投稿も全て削除される(ON DELETE CASCADE)
ユーザーに紐付く投稿がある限り削除ができない(ON DELETE RESTRICT)
ユーザーを削除しても投稿は残り続け、ユーザー情報との紐付けが切れる(ON DELETE SET NULL)
ユーザーを削除しても投稿は残り続けるが、投稿にアクセスすると参照エラーが発生する(外部キー制約なし)
親子関係にあるテーブルにCASCADEオプションを設定をしておくと、親を消したときに子のデータも一緒に消してくれます。ただしこれも状況によりけりで、親データが消えても子データが残った方が良い場合と両方とも同時に消えた方がいい場合があります。
同時に消えない場合でも、子のデータ内の親情報を消してしまうかそうでないかを設定することが可能です。たとえばユーザーが任意で属しているSNS内コミュニティなど、そのユーザーにとって必須なデータでない場合、コミュニティを削除したときにユーザーのコミュニティ情報をNULLにしてしまうことで紐付けだけを解除することもあります。
普段確認していること
とあるデータA(例:Xのポスト)を参照しているデータB(例:リポスト)があったとして、データBを作った後にデータAを何らかの形で参照できない状態にする(例:ポストを消す)とエラーになることが多いけど、この作業に通称みたいなのあるのかな
— かいり (@QA_kairi) April 8, 2024
私は心の中で「ハシゴ外し」と呼んでます🪜
削除に限らずですが、とあるデータBが何かしら別のデータAを参照していることがわかる場合は、そのデータAを参照できなくしてデータBの参照時にエラーが発生しないかをいわゆるエラー推測で探すことが多いです。
また、削除に関する処理でもデータを削除するとき子のデータが一緒に消える設定がされているのか、されている場合は本当に一緒に消えるのかを確認しています。CASCADE設定をして一緒にデータが消える想定でいたら、実はデータ削除形式が論理削除(外部キー制約が効くのは基本的に物理削除です)だったためにデータが消えていなくて参照エラー、という場面には実際に遭遇したことがあります。
終わりに
削除と参照エラーは怖い、ということが伝われば幸いです。
ここまでお読みいただきありがとうございました。