【SQL】【DB設計】delete_flagについて調べたこと

2022/07/23に公開

delete_flagとつけると、「削除していいもの」と思わせてしまう。

営業: これ削除ボタン押したら管理画面からも消えるんだけど?
エンジニア: え?当たり前じゃないですか
営業: あー困る困る。削除はユーザーさんから見えなくして欲しいだけで、管理画面では見える必要があるの。
エンジニア: ...わかりました(削除じゃねーじゃん!)。

アンチパターンの解説 - 3/8 より

「あるエンティティ定義に、論理削除有無を設定する属性が定義されている時点で、開発者は『ああ、この表のデータって削除していいんだ』という暗黙の了解に思考を縛られる」

参考: 論理削除が奪うもの

5年後のある日、新人エンジニアがサービス改修をしていた。
delete_flagをgroup byしてみると、

	SELECT delete_flag AS delete_flag FROM users GROUP BY delete_flag
		
----------
	1
	2
	0
	9
	NULL

delete_flagに2,0,NULL!?
先輩に仕様を聞いてみると

0: 未削除
1: 削除済み
2: 管理者による強制削除
9: 抹消
99: よくわからない
NULL: バグで入る

削除のコードを読んで、1が削除なのか、0が削除なのか、はたまた9が削除なのか調べる必要があります。

delete_flagをつけることによる弊害例3つ

SELECT bug_code, date_reported, summary
FROM Bugs
WHERE is_deleted = 0
  • 常にWHERE句が必要
  • コードが削除フラグだらけ
  • 認識の齟齬を生みやすい

SQLアンチパターン 幻の第26章「とりあえず削除フラグ」 スライド 17 /45 より

解決策

解決策への糸口→deleted_at(DATETIME)にする

→カラムにNULLが入るとインデックスを使えないためデメリットがある
→問題解決になっていない。(結局WHERE句を多用しなければならないし)

それはフラグではなく状態である

CREATE TABLE Bugs(
	id varchar(20) NOT NULL
	status varchar(20) NOT NULL
)

例えば、「有効、中止、キャンセル、廃止予定」のような状態だ

[SQLアンチパターン 幻の第26章「とりあえず削除フラグ」 スライド 34 / 45 より

履歴テーブルに移す

そもそも削除も更新もしない

アプリケーションは現実を何かの業務等々の観点で抽象化したものであり、それが扱うデータは事実に忠実にモデル化されたのなら残り続けているはずなのです。現実から事実を消し去ることは不可能。

T字型ER手法というのをベースにしたテーブル設計での原則

  • テーブルに状態を持たせない。
  • 究極には機械が認識するキーと、人間にとって意味のあるデータだけのエンティティだけで全ての業務のデータを構成できる
  • 日付をもつデータはイベント(これも一つのエンティティ)
  • NULLのデータは絶対に持ってはならない
  • テーブルはデカく作るな、小さく作れ
  • テーブル同士の関連は直接もつな、関連を表すテーブルを作れ
  • 1:1の関連になったとしても、イベントとそれに付随するデータは分離しろ
  • データが増える?金と物理で殴れ(ディスク増強しろ)

[SQLアンチパターン 幻の第26章「とりあえず削除フラグ」 スライドスライド 38 / 45 より

そもそもテーブルやレコードの中身がわかる適切な名前をつける

そもそもテーブルやレコードの中身がわかる適切な名前をつける
「失敗から学ぶRDBの正しい歩き方」より

テーブル名を見て中のデータを想像できないといけません。
データベース設計で絶対役に立つ命名規則

まとめ

  • 「とりあえず」が思考停止
    • 全てのテーブルに削除フラグはおかしい
  • 「削除」は設計不足を示す
    • お客さんは本当に「削除」と言っているか?
  • 「フラグ」以外もある
    • 状態遷移で考える方がマシ
    • 更新/削除をしない世界もある
  • それでもよく考えた末の削除フラグならOK

Discussion