データベースの論理削除 あり?なし?

LABO

はじめに

ネット上でいくつか、論理削除はSQLのアンチパターンとの話が上がっていました。
メリットデメリットが書いてありますが、現時点ではその主張が少々テクニカルな話に偏っているかなと感じられたので、運用面や使われるシーンとも絡めて考察してみたいと思います。

あくまで、業務システムでデータベースを利用する際の話であり、学術的なデータの集計なども加味したうえでのアンチパターンの指摘であれば、この考察の範疇外になります。

基本的に私は論理削除派なので、反論というよりは物理削除が良いとされる内容と、私の行っている実装とを比べて、実は論理削除よりも良いものがあるのであれば活かしたいという意図もある。
そういった思考実験的に頭の整理を兼ねています。
なお、私自身、物理削除のシステムも扱っているので、論理削除だけの経験から判断している訳ではありません。
なるべくバイアスがかからない様に心がけて考えてみますが、難しいと思いますので突っ込みをお待ちしています。

物理削除、論理削除が何者なのかについてはここでは説明しません。

私が論理削除を選んでいる理由

いきなりバイアスをかけてしまいますが、私がなぜ論理削除を選んでいるのか?
考えなしにとりあえず削除フラグとしているわけではありません。
それを覆す発見があるのかが今回のテーマなので先に伝えます。
逆に物理削除方式で以下を守るための方法等も考えてみたい。

  • 何が何でも顧客のデータは守る。
  • 顧客の活動を極力止めない。
  • 必要以上に凝った仕組みにして運用コストをあげない。

メリット/デメリット

よく言われているメリットデメリットです。

物理削除論理削除
メリットストレージを圧迫しにくいストレージを圧迫する
デメリット一度削除してしまうとデータを復元できない削除されたデータの復元が簡単にできる
性能低下に繋がりかねない
抽出クエリに削除フラグの条件が必要
その他(対となる主張が不明確なので分かり次第追記)心理的な削除に対する不安をデータ保持で解消している
削除フラグという状態管理が不要削除フラグという状態管理が必要

これらのメリット、デメリットがどのように影響するのか一つづず考えてみます。

物理削除はストレージを圧迫しにくい

(⇒論理削除はストレージを圧迫する)

物理削除はストレージを圧迫せず、論理削除はデータが残るので圧迫する。
さて、これは正しいか?

論理削除は、物理削除ならきれいに消してしまうデータを残すわけなので、容量を多く要するというのはその通りである。

ストレージを圧迫することの弊害

圧迫した際のことを考えてみます。
圧迫して余裕がなくなってしまったら、どうなるのか?

データベースがデータを格納するブロックを拡張できなくなります。
もちろんデータ登録ができなくなります。
対処はストレージの容量を増やすしかありません。

だがこれは、論理削除の問題だろうか?

まず、データの増加量を加味して運用に耐えうるストレージ量を、そうならないようにするのが設計の仕事です。
論理削除なら論理削除なりのデータ量設計を行うのでその点で、圧迫するという事は無いと思われる。
圧迫する状況自体が設計段階での誤りであって、それは物理削除であろうが同じ問題をはらんでいると考えられる。

その為、これを物理削除のメリットと言われて、ピンと来ていない。

ちなみに物理削除をしておけば単純に容量が少なくなるかというとそういう訳でもない。
実はDELETEでデータは削除されても、データベースから情報が無くなっているわけではない。
内部的に削除されたという状態を保持しているにすぎず領域は占有されている。
その為、これが解消されるまでは論理削除とあまり変わりはない。
データベースが勝手に保持しているか、ユーザ主導で保持しているかの違いでしかない。

これは、DELETEやUPDATEによるフラグメンテーションによるものです。
これを解消するためにデータベースに対しデフラグを行うことになる。
これをして初めて物理削除したレコードの領域が解放されるので、定期的なデフラグの運用はどんな設計であろうと必須です。
なので、この頻度によっては物理削除であろうが、論理削除と扱うストレージ量にあまり差がでない可能性すらある。
24時間稼働のシステムでなければデフラグをスケジューリングしておけばいいんですが、24時間のシステムだった時は大変でした。

情報の保持期間

また、これもシステムの要件にはなりますが、情報の保持期間というものを設定する場合があります。
法律で決められた期間である場合や、社内の規定で決められた期間、個人情報などはプライバシーポリシーで謳っている期間しか持っていてはいけないものもあり、戸籍情報みたいな永劫的に残すような情報でない限り、多くは一定期間で削除されていきます。
ある条件下で不要になったものを削除する「削除バッチ」などの処理で行われます。
もちろんこの際に行われるのは、論理削除で構築されているシステムだとしても、物理削除だ(もうシステムの中に不要と判断されたものだから意味合いが違う)

こんな感じで、ある時期から(この例では5年保持)データの総量は変わらなくなる。
不要なデータから削除されることによって、データの登録数と、削除数が拮抗するはずである。
実際にはサービスの拡張などで徐々に増えるケースが多いが、それは拡張案件時にストレージの見直しをすることになる。

だいたい、この落ち着く年度までの増加量を想定して容量の計算を行っていく訳なので、いずれにせよ急激に枯渇するような場合は、ストレージの容量設計ミスってことになるだろう。

この観点から、これは物理削除、論理削除の問題ではないと考えられるため、私は物理削除のメリットとは現段階では考えることが出来ないし、論理削除のデメリットとも思えない。

論理削除はお金がかかる

次にお金がかかる問題だが、確かにデータ量は、物理削除<論理削除となる。
では、いかほど金額に差が出るのか?という話になってくる。
論理削除は物理削除の何倍くらい容量を使いそうかイメージだけで話してもしょうがないので、モデルケースを考えてみたいと思う。

自分の経験したシステムのケース

まず、どれだけ容量が物理削除より多くなるかは、削除の頻度にも関わってくる。

携わったシステムを顧みると、わざわざ削除するケースって操作を間違えて登録したデータや、ユーザデータの様な定期的に人事異動などで入れ替わる人の管理、等が考えられえるが、その頻度はどうだろう?

例えば、いつも使っているシステムで100回に一回くらい間違った登録をしてしまったとすると、かなり乱暴だが、システム内で使用されるテーブル全てで同じ登録ミスが発生するとして、1%程度余計に物理削除よりかかることになる。

その中で使われるユーザデータにしても、離職率10%としてもユーザテーブルのみ10%余計に物理削除よりかかることになる。
でも、ユーザテーブル何て物はシステムの中でも一番小さそうなテーブルであるし、レコード数もそうないことを考えると、誤算の範囲と思える。

「1%とは乱暴な、もっと削除する様な場合もあるだろう!」という意見があるかもしれない。
「例えば10回に1回失敗する様な…」
もしも、そんなに削除しなければいけないような失敗を繰り返すシステムは、UIの方に何らかの問題があるのではないだろうか?
フラグ云々の前にユーザフレンドリーに間違えを回避するユーザーインターフェースを考える方が先だろうと思う。

次に、論理削除をするためには、それを格納するフィールドを設ける必要があります。
基本的にフラグで管理するので、各テーブルに1バイトのフィールドが余計に必要になります。

その1バイトが「1レコードにしめる割合は?」と言うと、多分1%にも満たない。
仮にこれも乱暴に1%レコードのサイズが増えたとする。

上記の例では2%くらい物理削除より容量がかかることとなる。
あれ?思ったより全然違いがない。

常に登録と削除を繰り返すようなシステム

もう少々、削除が頻繁に行われるシステムを考えてみる。

さて、どういうシステムだろう?
私の経験の範疇では思いつかないので、こういうシステムがありますというのが合ったら教えてください。

仮に毎日登録データの50%が削除されるようなシステムがあったとして(100%じゃデータ残らないもんね)、この場合は確かに論理削除は物理削除よりも50%余計にデータ容量を持つことになる。
つまり2倍だ。

こういったシステムがあったと仮定すると確かに、容量は多く使うことになるので影響は大きい。

だけど、やっぱり上記の様なシステムがあったとして、ユーザが積極的に削除を繰り返すような要件が思いつかない。
もし、バッチ処理などで行う削除処理だとしたら、それはデータベースに登録するデータの取捨選択を登録前に行う必要があるんじゃないかな?
と思ってしまう。

金額は?

これは、ピンキリなので何とも言えませんが、オンプレミスであればサーバー向けのストレージを購入するでしょうし、まぁ故障を考えてRaid 1,0+1,5みたいな構成を考えるでしょう。
クラウドであれば「完全性/可用性/機密性」をどのレベルで担保するかで選ぶグレードも変わるでしょう。
そうなると絶対値での金額は言いずらいですが、物理削除と論理削除の相対的な金額で言えば

私の経験したシステムの様な構成であれば2%増し?(みたいなことにはならないかな誤差の範囲)
論理削除ストレージ金額 = 論理削除ストレージ金額 × 1.02

常に登録と削除を繰り返すようなシステムであれば、2倍くらい?ってことになるのかな?
論理削除ストレージ金額 = 論理削除ストレージ金額 × 2

ストレージに関する今時点の結論

今時点では、私の経験の範囲では2%増加するくらいならストレージの観点では差は無いと考えます。
なので、現時点では私がこれを理由に物理削除を使うことは無いと思います。

ですが、私の経験したことのないシステムではストレージ圧迫が問題になるケースもあるかもしれない。
ですので、情報の保持に関する要件によってケースバイケースであろうとは思います。(弱い)

なお、繰り返しになりますがこういったシステムがありますという物があれば教えてください。
所詮一人が携われるシステムは多くても10を数えないでしょうから。
未知なるシステムに少々興味があります。

論理削除は削除されたデータの復元が簡単にできる

(⇒物理削除は一度削除してしまうとデータを復元できない)

これは、論理削除を使用している理由の一つでもあるので、特にバイアスがかからない様に、慎重に考えてみたいと思います。

論理削除の場合の復元

他のサイトでも書かれている通り、削除フラグを戻せばデータは復元します。
でも、実際はそんな簡単には作業はしていないのですよ。

  • 復元させることの影響の調査
  • オンラインで作業して問題のないデータなのかの確認
  • オンライン中ならそのデータを取り扱う部署との調整
  • 復元の作業

という工程をへて初めて作業をするので、イメージ程お手軽ではありません。
これが一般公開されているサービスの場合は基本オフラインでしか作業できないと思われますので

  • 作業のためのサイト停止のスケジューリング
  • 一時的にサイトをサービス停止する旨の案内
  • 作業
  • サイト再開の案内

の様な作業が必要になる場合もあり、いずれにせよデータを復元させるというのは簡単に出来る作業ではありません。

ですが、物理削除との決定的な違いは「既に一度登録された情報を再利用できる」これにつきます。
もちろん、基本は論理削除であっても「もう一度登録してください」です。
そうもいかない場合に削除フラグを戻すという作業を行うことになります。
その作業の一端だけ見ると「削除フラグの更新」となるのでお手軽に見えるのだと思います。
これは物理削除も同じと言えますが、物理削除した場合はもう少し手順が増えます。

物理削除の場合の復元

物理削除の場合も論理削除の復元と同様行うことはほぼ変わりません。
大きく異なるのは削除された情報はシステムの中には存在しないという点です。
これによって、一番の大仕事

  • 復元させるデータのヒアリング

を行うことになります。
その後の工程は同じですが、復元の作業の仕方が異なってきます。

復元させることの影響の調査

  • オンラインで作業して問題のないデータなのかの確認
  • オンライン中ならそのデータを取り扱う部署との調整
  • 復元の作業

復元させるデータのヒアリングの何が大変か

まず、一般ユーザというのはITリテラシーはそんなに高くない(失礼な言い方ではあるが)。
システムは何となくちょちょいと簡単に出来るというイメージを持っている。

どういうやり取りが発生するかは、こちらを参照してほしい。
一例をあげています。

また、複数人で扱うシステムでは登録した人とは、別の人が削除する可能性もある。
そうなると「誰が」「何の理由」で削除したのかも合わせて知る必要があります。

まず、お客さんはシステムを利用したいのであって、自分の仕事の一部分をシステムに任せているに過ぎませんので、言えば時間を取ってもらえるという思い込みがまず間違いです。
その為、限られた時間の中でヒアリングを行うことになるので、ヒアリングする内容も事前に吟味が必要です。
そして、この過程に掛かる時間が非常にかかる(ことを知っている)。

そういった、自分以外の人の時間の調整も含めて作業をする大変さがあります。
いわゆるシステムのテクニカルな話ではないですが、システムを預かるということはテクニカルな対処だけでは対処できないこともあるということです。

この辺に時間をかけることは「顧客の活動を極力止めない」に反してしまうこともあり(もちろん論理削除だから問題ない訳ではないですが)、なるべく「以前に登録した内容を復元するので後は宜しく」というスタンスで行いたいという思いがあります。

物理削除でも復元するデータをデータベースとは別に保持

では、物理削除でヒアリングすることなしに復旧するには?
いくつか手段がある。

  • ジャーナルの導入
  • 履歴テーブルへの情報保持

いずれも、テーブルから削除する代わりにどこかに削除前の情報を保持して置きましょうということです。
だが少し待って欲しい、この対処をすると「物理削除はストレージを圧迫しにくい」に反してしまうではないか。
データベースは圧迫しないが、他の要素で圧迫するのでは本末転倒になってしまう。
なので、やはり物理削除でストレージの要件も合わせて考えると、方法が無くなってしまう。

結局のところは、物理削除するという行為は「削除した責任はお客さん」という、要件のもとに成り立つシステムということになる。
これは、決め事の問題なのでこの要件で問題がないのであれば、それに越したことは無いし、私も物理削除を選ぶだろう。
だが、残念なことに今まで私はそういったシステムに当たったことが無い。
「そうはいっても何とかしてよ」と、なることが多い。

まぁ、考えてみればソーシャルゲームで不注意でロストしたキャラを「復活させてよ!」みたいなのも同じよね。
「出来ません!」っていう運営のゲームより「何とかします!」っていう運営のゲームの方が安心できるしね。

復元の作業

物理削除した場合の復元は、Insertで行われます。
事前にヒアリングしたもので、Insert文を作ることになります。

システムを操作して登録しなおすのはお客さんにお願いすることと同じなのでここでは考えません。
それが許されるなら論理削除も復元方法は同じになってしまうからです

ここで、Insert文を自前で作ることと、Update文でフラグを変更する違いの他に難しいところを記載しておきます。

  • Insertテーブルにバイナリ項目を含む場合
  • Insertテーブルに独自の暗号化項目が含まれる場合
  • InsertテーブルにAutoNumberの参照キーを含む
  • 参照整合性の縛りが厳しい場合
Insertテーブルにバイナリ項目を含む場合

これが意外と面倒なのです、バイナリファイルをサーバに上げたり、SQLからパスの通ることを確認したりと、一手間も二手間もかかります。
これは、行ったことがある人であれば分かって貰えるとと思います。

※論理削除の場合はレコードにバイナリの項目もそのまま残っています。

Insertテーブルに独自の暗号化項目が含まれる場合

データの中には暗号化されて登録される項目などがあります。
暗号化する為には、システムで行っている暗号化手順と同じ手順で暗号化する必要があります。
これがSQLを作成するさいに再利用できないと、少々手間です。
複合可能な暗号であれば、暗号化した文字列を複合化して確かめることも出来ますが、ハッシュ化されている項目(主にパスワードみたいな項目)は、そのハッシュ化した結果が正しいかは不可逆なのでシステムで扱ってみるまで分かりません。
もちろんテスト環境などで確認はするでしょうが。

※論理削除の場合はレコードにシステムで暗号化された内容がそのまま残っています。

InsertテーブルにAutoNumberの参照キーを含む

データベースの設計がサロゲートキーをベースに行われているケースは、キーがAutoNumberで設定されているケースがあります。
こういったケースでは、Insertで以前のキーを復元することは出来ません。
その際に以前は紐付いていたであろう、他のテーブルの参照キーを更新するなどの手間が発生する場合があります。
また、これらはERDを正しく把握していないと、修正の結果が正しくリレーションされないなどの問題もはらみやすく、慎重に作業を進める必要が出てきます。

※論理削除の場合は採番されたキーがそのまま残っています。

参照整合性の縛りが厳しい場合

データベースに参照整合性の設定がされている場合、複数テーブルへのInsertに関しては、順序性を考える必要がある。
親→子関係のテーブルを複数メンテする場合など、思いがけないところでInsertが失敗することがあり、準備が面倒になる。
もちろんテスト環境などで確認段階の話で作業時には手順化されているでしょうが。

※論理削除の場合は参照整合性の取れた状態のデータの更新なので、問題はありません。
 その代わり、論理削除での参照整合性って意味ある?って議論になります。
 なので、私の携わっている多くのシステムは参照整合性をデータベースで判断せず
 プログラムで判断するような仕掛けになっています。

復元に関する今時点の結論

復元をするという作業を考えてみると、今の処テクニカルな面でも論理削除の方がメリットがありそう。
また、論理削除は「何が何でも顧客のデータは守る。(バイナリだろうがハッシュされた項目だろうがね)」「顧客の活動を極力止めない。」「必要以上に凝った仕組みにして運用コストをあげない。」のいずれの面においても、要件を満たしているので、この面からみると今のところ論理削除一択かなという結論でした。

物理削除の復旧方法として、ジャーナルや履歴テーブルをあげてみましたが、他にもこんな物があってそれを使っていると言う事があれば教えてください。

論理削除は性能低下に繋がりかねない

(⇒抽出クエリに削除フラグの条件が必要)

この二つのデメリットはデータベースアクセスの観点では同じことを指している部分もあるので、合わせて考察します。

まず、必ず言われるのが論理削除では削除フラグが追加されることにより、削除フラグが立っていないものを前提としたSQLを記述しなければならないということ。
物理削除では意識することなく存在するデータは全て生きているデータと判断されるので上記の様な条件を前提とする必要がない。
これに伴って、カーディナリティーの低い項目での検索になるので性能が劣化するとの指摘である。

これは正しい指摘か?

カーディナリティーの問題

テクニカルな話だけでしてしまえばこれは正しい。
しかし、これは削除フラグだけを条件として検索を行った場合の話である。
運用面で考えた時、削除フラグだけで検索されるケースがあるか?

物理削除で言えばテーブルの全項目、つまりフルスキャンする処理
論理削除で言えば削除フラグの条件で検索されるレコードの抽出処理

つまり、システム上のオンライン処理で全件抽出する処理でもなければまずないし、そんなことを要求されたら、まず設計段階で断ります。
別の手段で全件渡す方法を検討すると思う。
※夜間にバッチで行う様な処理を想定しているのであれば、こんな議論が起こらないと思うので

仮に全件抽出するような要件があったとして

まず、削除フラグにインデックス何て張ることはまずありませんが、仮に削除フラグでの全件検索があったとしたら、まずは、Oracleならビットマップインデックスってのを使って効果があるか測定します。(あまり効果がない場合も多いし対応していないDBも多い)
効果がなければフルスキャンに任せます。
基本的に「削除されていないデータ>>>>削除されているデータ」になると思いますので、削除されていないデータの検索にインデックスを使用するぐらいなら、フルスキャンさせた方が早いと思います。

どのくらいの時間の差が出るかは、レコードのサイズと件数によるところもあるのが、まずこの要件が出るときに想定されるレコード数はどのくらいか?

多分であるが、全件抽出と言っても、エクセル上で操作できる範囲くらいしか必要としていないテーブルのデータと考えられる。
例えば、全職員、全商品みたいな、一定期間でデータ量が劇的に増えないデータである可能性が高い。
期間でデータが増えるのであれば、期間指定するであろうしそうなると削除フラグのカーディナリティーの話ではなくなってくるから。

そうすると、あっても数千レコードのテーブルで、項目数もあっても100~200程度のテーブルの話になってくると思う。
でなければ、手元にそんな資料貰っても多分見もしないと思う。
であれば、この程度のデータではフルスキャンしようが対して時間はかからないので、フルスキャンして削除されているレコードをプログラムで排除したほうが早いかもしれないし、そうなると物理削除のときと大して時間も変わらないんじゃないかと思う。

※もちろん削除されるレコード数が半数以上を占めるとなれば別だが、それは設計ミ…

運用面で考えた場合のカーディナリティー

まず、論理削除でフラグをもっていますが、削除フラグにインデックスを張ることはありません(私の場合は)。
基本的に単一のデータを扱うのであればユニークスキャンになるはずで、その場合ユニーク項目に設定されたインデックスが有効になるので、まず削除フラグの条件による速度低下などあり得ません。

また、一覧系の画面や、一覧帳票を作成するような場合でもとても見切れないような抽出をする物は、ユーザーインターフェースとして誤っていることが多いと思われる。
昔某システムでレビューの際に指摘されて意識する様になってから、必ず聞くようにしていることがあります。
「一画面で100件を超える様なデータを扱う時、帳票で1000行を超える様なデータを扱う時、それは抽出することが目的になってしまっていて、実際にはそんなものは使われない。だから、本当に必要なものが何なんかもう一回聞いてこい」と、突き返されたことがあります。

実際に要件を詰めていくと、大量処理するような集計処理や、バッチで置き換える様な処理以外でそんなに大量のデータをオンラインで必要となることはほぼありません(私の経験では)。

大量データの処理を行う時にはそれなりのインデックス設計をするし、オンラインで100件や、1000件程度に絞りこむ要件があれば、かならず削除フラグ以外の絞り込み条件が発生します。
その場合は、その絞り込み条件でインデックスの設計を行うので結果、削除フラグがあるからと言ってカーディナリティーが低いかというと、そもそも使わないので意味をなさない(厳密には意味を成す=影響があることは理解していますが、議論するほどの影響は無い)。

なので、実際に運用で使用するデータベースの設計で削除フラグを単体で使うことが無ければ、この議論は意味をなさないと思われる。

プログラミング時の問題

次に言われることは、プログラミング時にかならずクエリに削除フラグを条件に入れる必要があり、それを忘れる事によるバグの誘発の話がある。

この指摘は、論理削除派には痛いデメリットをつかれたと思うことでしょう。
実際にこれによる不具合を経験していますし、都度この点の確認が欠かせなくなります。
開発コストも大幅に増加するのでは?

と言う所までは行かないように、私は工夫しています。

これは、開発において各プログラマーが個別にSQLを記述する開発においてはこの指摘は正しい。
一方でこの労力が必要なことは論理削除を選んだ時点で、多くの開発者は理解している。
理解しているからこそこの点のミスを吸収する施策を検討して進めている。
無策に開発を行っているわけではないのだ。

また、この指摘のケースは開発規約の範囲内で、プログラマーが自由にSQLを記述することが考えられる。
この際、人為的なミスがプログラマー単位で発生する可能性があり、実際こういった開発を行っていてフラグの参照が漏れていて不具合を起こすことがある。
特にすべての抽出系SQLに気を遣う必要があり、物理削除と比べて気を使う場面は多い。

方や物理削除派そんな心配は無いかと言うと、同じように条件句には気を使わなければならない。
それは、誤った削除条件にしてしまうと、データが消えてしまうという事だ。
論理削除とは違い、逆にこの点に気を使わなければならない。

こういったケースは多分、開発がこんなレイヤーで進められているケースだと思う。

開発規約のみが開発者に提供され、データへのアクセスを各々のプログラマーが作成していく様な開発だ。
レイヤーで言うと、開発規約が全てのコーディングのルールになっているケース。
こういったケースは論理削除での開発に限らず、プログラマーの裁量で行えることが増えるので、同じような問題が物理削除の開発でも出てくるものと思われる。

論理削除開発での考慮

さて、ではどのように工夫しているか?
私の場合は開発部品(ライブラリ等)のレイヤーが一層追加になっており、O/Rマッパーもどきを作っています。
開発者は提供された部品を使用してコーディングするため、個別にSQLを記述することがありません。
部品を作る担当者が限られるので、全プログラマーのレビューは必要ありません。
こうすることで、削除フラグの記述は部品が一手に担うことになるので、不具合があったとしても部品作成時の単体試験でほぼ抽出することが出来ています。
※私はちょっと特殊な開発フレームワークで行っています。

不具合の影響

これは実際に経験した不具合の例です。
開発規約のみで行っていた例で誰も気が付くことなくリリースされた物です。
これらの経験から、論理削除を選んだという経緯もありますので例示します。
なお、物理削除でも、論理削除でも不具合を経験しています。
一番怖いケースとは書いていますが、個人の感想です。

物理削除で一番怖かったケース

ある削除処理で条件が動的に作成されるDELETE分でした。
ですが、ある一定条件下で実行されたとき、DELETEのWHERE句が機能せず、全件削除になるという不具合をはらんでいました。

論理削除で一番怖かったケース

論理削除の条件で削除フラグを判定する記述が漏れており、不要なデータが計上された。

上記の2例から分かる様に、どちらも条件句がらみの不具合ではあるが、物理削除、論理削除に限らず不具合は起きるということだ、それを未然に防ぐ仕組みが大事なのであって、どちらを選んだから大丈夫ということはないと考えている。

さて、だが次の観点において、どちらの不具合がダメージが大きいかを考えてみたいと思う。
これも実際に経験したことから

物理削除の不具合発生から復旧までの一部始終

業務システムにおける最優先事項は「何が何でも顧客のデータは守る。」だ。
何度かニュースを賑わせた、ネット上で炎上したシステム系の失敗談の中でも、致命的なのが顧客のデータが守られなかったことだ。
物理削除で考えうる最悪の不具合は、誤ってデータを削除してしまう事だ。
このミスが無いと言い切れない、何故なら人間は絶対に失敗をするから。
論理削除の不具合では、最悪データを消すことが無いが、物理削除ではある。
この違いは非常に大きい。

馬鹿なと思うかもしれないが、実際に私の関わった案件でも発生している。

その際には、以下の手順で何とか復旧することが出来た。
・デイリーでバックアップを取っていたので、前日夜間の状態にロールバック
・当日行った作業は、操作履歴に相当する情報と登録内容のジャーナルに相当する物があったので、そこから当日作業分の情報を復元
・復元には急ごしらえの復旧ツールで作業
だが、当日の作業はあきらめてもらって、上記の作業を一晩で片付けなければならなかった。
これは、物理削除をするうえで最悪を想定してリカバリ設計として復旧できる情報を保持することとしていたから成し遂げられた。

復旧は出来たものの「顧客の活動を極力止めない。」「必要以上に凝った仕組みにして運用コストをあげない。」の二つを満たすことが出来なかった。

たらればに、なってしまうがこれらの経験から、現在は論理削除+履歴テーブルという構成で設計する様にしている。
履歴は内部統制上の理由から用いられることも多く(嫌な話だが犯人捜し)、復旧を目的としていないがこの構成であれば、直近の履歴からカレント情報を復元して更新をかけると言う対処が出来るので、場合によってはオンラインでの復元も出来たかもしれない。

心理的な削除に対する不安

どこで目にしたかは定かでなくなってしまったが、論理削除は削除の不安を紛らわすために行っている手段との意見があった覚えがある。
正直その通りのところはあると思うが、私としてはここまでに挙げてきた論理削除を選択している理由によるところが大きい。

そのうえで物理削除でのこの不安の解消は「心理的な削除に対する不安はテストで解消」ということなのだろうか。
もしくは、削除した内容は履歴テーブルなりに退避かな?
元記事がわからなくなってしまったので、意図するところが明確ではなくなってしまったので、見つけたら追記します。

物理削除は削除フラグという状態管理が不要

(⇒物理削除は削除フラグという状態管理が必要)

これは、ステートレスな設計か、ステートフルな設計かという話から出てきた内容だったと記憶している。
データに状態を持たせるなという話だと思うが、データに状態を持たせない場合、データベースの項目に状態に変わるものが必要になってくる。
もしくは、データの項目の組み合わせで判定できる条件を設計するか。

データの項目の組み合わせで判定できるなら、フラグは不要だと私も思う。
このケースのフラグを持つことは、項目の冗長化ともいえるからだ。
しかし、この状態の組み合わせとは簡単に複雑化する…例えば、白か黒か?という単純な条件でも10個も重なればバリエーションは簡単に1,000を超える。

実はそういったステートレスな設計を行ったこともあるが、結論から言うとある程度データベースに状態を持たせないと、私が携わっている様なシステムでは実現が難しい。
ステートレスな設計はシンプルな設計の実現であるはずなのに、アプリケーション側の判定条件が複雑化ししてしまい、システム全体としては本末転倒になってしまう。

笑い話だがこの条件をドキュメントに落としてユーザにレビュー依頼をした際の様子がこちら

この時のユーザは本当に真剣で設計書も丁寧に読み込んでくれました。
いまだに、このレベルのユーザに出会うことはないですね。
ちなみにこの時の仕組みは、カレントテーブル+アーカイブテーブル+ジャーナル+ロールフォーワードで、顧客からシステムに一度リクエストがあったら、絶対登録まで通すというとんでもないものでした。
もう、関わりたくはないですね^-^;

まぁ、いろいろな経験から私の力量ではステートレスな設計はかえって、システムを複雑化させるという結果に至り、データベースに状態を持たせることの方が物事を簡略化させるという結論に至りました。
故に削除フラグを持たないとステートレスに実現できるとしても、ステートフルに判断する方をとる方がシンプルという結論になりそうです。

実はこんなことを言われる場合も

少々、削除フラグとは異なる話題かもしれませんが、結構こういうことを言われる場合があります。
こういったケースも論理削除しておくと仕組みを複雑化することなく対応することができる。

マスタとしては削除扱いにしたいけど過去の情報も見たい

とあるシステムで取引の情報はメインとなるテーブル、に対して顧客の情報や、商品の情報はマスタ化されているとします。
この情報をもとに画面に表示したり、帳票を印刷したりしています。
よくある一般的なケースです。

ですが、ある顧客との取引がなくなったことにより、もう登録時にその顧客の情報を選択できないようにする必要がありました。

マスタから顧客情報の削除です。

でも、単純にデータを削除してしまうと「そういえばあの取引ってどうだったっけ?」と、過去の取引情報を見たい時に困ります。
SQLの組み方によっては必須項目のリレーションならInner Joinにするでしょうから、そうすると過去の取引情報事態が見られなくなってしまうという副作用も考えられます。(参照整合性をデータベースに持たせれば別でしょうが、その場合はこのケースではデータを消せなくなります)

この時に論理削除にしておくと、登録時は見せない(削除フラグがたっていないものだけ検索)、参照時は削除されたものも見せる(削除フラグがたっているものも含めて検索)の様な対応も可能になり、使い分けができます。

ちなみに、物理削除してまうとこういったケースの過去の取引情報が見えなくなってしまう場合もあるので、何らかの対策が必要。
結局はこういった要件があると、削除したデータをどこかに保持しておくほかない。
また、例えば外部ファイルにとって置く場合は、上記のような過去の取引情報を見ようとすると、データベースだけから情報を取得するわけではなく、外部ファイルとも結合した条件で見なければならないので、かなり処理は面倒なことになります。
すると、外部ファイルに取っておくくらいならフラグを付けておく方がシステムも簡易になると言うものです。

今月退会した会員のリストが欲しい

これも似たようなケースですね、会員管理なんかをしていると会員の入退会の推移なんかを見たくなります。
この時、退会したからと削除してしまってはそういったレポートを作ることはできません。
といっても、ちょっと昔にあった話です。
今の時代は退会したら会員情報の削除証明みたいなのも必要な時代ですので、会員の情報をそのままシステムに残すわけにはいかないんですけどね、会員の特定はできなくしつつ匿名の統計データとして残すくらいしか。
しかも、その承諾も必要という…なかなか大変な時代になりました。

さいごに

結局、物理削除の利点とされているものに、あれやこれやと反論する文になってしまった。
否定しているつもりはないのだけれども、こういった苦労があったなとちょっと思い出してしまったものですみません。

結局のところは適材適所(おい!)で、私のいる世界の範囲では論理削除のほうがメリットあるなということなのだと思います。
物理削除が悪いわけでも、論理削除が悪いわけでもなく、使いどころが違うということなのだと思います。
物理削除はこんなところで活躍しているよという、違う世界にいる人は私にそれを教えてください。
とても興味があります。

だから、どっちがアンチパターンとか、そういう事はない気がします。
そんな攻撃合戦はやめて、それぞれの利点を知って次に活用するって事が大事な気がします。
そもそも、もうどちらかが正しいと結論が出ているなら、議論の余地はないですしね。


コメント

タイトルとURLをコピーしました