CRのみデータベースはどうだろう

2024/1/26作成

私の職業は流しのプログラマなので、あちこちの開発現場を転々としています。そこではいろんなシステムが動いているのですが、当然にそれぞれビジネスの中核を担うような重要なデータが格納されています。

例えばECサイトのデータベースですと、商品データとかユーザデータも重要ですが、何と言っても重要なのは受注データではないでしょうか。受注することで売上という企業の根幹の取引が発生し、その証跡となるものですからね。いやまあ、もちろんユーザの個人情報だって大事だし、それぞれ大事なんですけれども。

そんな大事な受注データですが、これまた当然にデータベースに格納されています。世間的には Oracle とかが強いんでしょうが、私が渡り歩いている現場では MySQL が多かったですね。

で、個人的に思うのは、そんな大事な受注データなのに、普通にデータベースに格納されているところばっかりなんですね。これ、怖くないのかなと。何が怖いかっていうと、このデータが改ざんされたり、削除されたりとかしたら、受注の証跡がなくなって、売上もなくなってしまいますよねと。

そりゃま当然にバックアップは取られていますから、ハードウェア障害とかでデータが吹っ飛んでも復旧はさせられます。どっちかというと怖いのは、そういう全データ消失とかの大規模な場合ではなく、一部のデータがこっそり書き換えられていたとかの場合。

現場によりますが、本番データベースにアクセス権を持つエンジニアはそれなりの人数になります。その中に心得の悪い奴がいて、こっそりとクエリ叩いてデータを書き換えてしまうかもしれない。もちろんそんなことをするのは悪いことですし、場合によっては犯罪でもあるのですが、全ての関係者が善良であるという前提にたって運営するのも少々お花畑過ぎる気がしないでもない。

悪意をもってデータを書き換えられるよりももっと深刻なのはプログラムミスによるものです。データ更新処理において対象絞り込みの条件が間違っていて関係ないレコードまで更新してしまったというのはあるあるなバグですね。月次処理をしててどうもおかしいなと調べてみたらバグが発覚したけど、間違って更新されたレコードが膨大だし、かといってバグ発生時以降の新規に受注データも大量にあるから以前のバックアップを戻すってことも出来ず、対象レコードをちまちまと復元しなきゃいけないなんてことも、ままある話です。実際にそれに近しいことを経験したこともありますよ。

システム側でも当然に更新履歴はとってますよ。大抵はレコードごとに作成日時と更新日時のカラムは持ってますので、改ざんされたレコードをある程度特定することは出来ます。しかし、更新前のレコードの状態全ては保存していない。更新ログを残しておくという方法もありますが、ログは膨大なので全てを残しておくことは現実的ではない。ということで、個々のレコードの更新履歴なんてのは現実的には分からないんですよね。

こういうことが起こるのは、要するに重要なデータなのに書き換えが出来るようになってしまっているからだと思うんですよ。そこでそもそもデータベースの書き換えが出来なくしてしまったらどうかなと思うんですね。データベースの機能はCRUDと呼ばれます。Create/Read/Update/Delete の4種ですね。このうち更新系はUpdate/Delete の二つですから、更新を出来なくした Create/Read のみのデータベースを用意したらどうだろうということですね。つまり CRUD データベースではなく CR データベースと。

具体的には MySQL では GRANT 文で INSERT と SELECT のみが出来る権限のユーザを作成し、普段のアクセスにはこのユーザを使うというわけです。もちろん管理者アカウントでは従来通り CRUD の全てが出来るのでデータ更新を完全に防ぐことは出来ませんが、それでもカジュアルなミスから守れるだけでもだいぶ違うんじゃないかと思うですよね。

こういうシステムの場合、データの扱い方にも少し注意が必要になります。データが更新できなくなりますから、既存のレコードを更新するのではなく、更新情報を追記するというスタイルになります。最新の情報を取得するにはキーで絞り込んだ更新履歴群の中から最新の更新日時のレコードを取得するという処理を常に行わないといけないわけです。これでは処理速度も心配になりますから、参照用の最新情報のみを格納するデータベースというのを別に用意するなどの対策も必要になりますかね。また、改ざんから守るべきデータというのは全てではありませんから、CRUD 出来るデータベースと CR のみのデータベースを分けて構築・運用しなきゃいけません。

ということで開発も運用もそれぞれ大変にはなりますけれども、データ保護という意味では格段に向上しそうな気はします。ただ、そういう運用をしている現場ってこれまでにはみたことはないんですけどね。なんでだろ。多分だけどエンプラ系のシステムでは当たり前に導入されてる考え方ではないのかなぁと思うんですが、エンプラ系は全くタッチしたことがないのでわからなかったりするのですけれども。

(2024/1/28追記)

この追記のみって考え方、紙の伝票時代にはむしろ当たり前だったんですよね。実際には私はその時代の商売を経験してないので、伝聞でしか知らないのですが。

注文があれば伝票を切るわけですが、注文内容とか伝票記載にミスがあった場合、伝票を書き換えるのではなく、修正のための赤伝票を切る。間違えたことも含めて全て記録には残しておくわけですね。決して一度発行した伝票を改ざんしたりはしない。複写式伝票にして分散して持つことで改ざんそのものも防ぐようにされている。

今のシステムでも、よほどの素人が作った者でない限り、注文履歴は追記するように実装していると思います。が、その基盤であるデータベースが改ざん容易であるってのがこの記事で言いたかったことです。はい。改ざんを検証できればいいんだったら、例えば注文レコードのハッシュ値を別システムに常に転記しておくとかでもいいかもしれませんね。証跡のためであれば、むしろそっちの方が適切ですかね。

(2024/2/4追記)

CRデータベースのメリットを一つ追記。

ECサイトで注文があったら、通常は注文レコードに商品マスタの内容をコピーしますよね。なぜなら商品マスタは更新されうるから。商品説明の誤字を直すくらいならともかく、価格などの主要な項目だってCRUDデータベースでは修正し放題です。かといって注文後に価格が変わってしまったら大問題。ということで、注文があった際の商品マスタのスナップショットを注文テーブルにコピーする必要があるわけです。

これで注文後に商品マスタが変更されても平気なんですが、問題はデータ量が肥大化すること。商品マスタが更新されうると言っても、実際にはそんなに頻繁に更新されません。ということは注文テーブルにはひたすら同じ商品マスタデータがコピーされ続けるってことですね。これ無駄ですよねぇ。

そこでCRデータベースです。具体的には商品マスタをCRデータベースに置くようにするわけですね。そうすれば商品マスタは書き換えられません。変更したいときは常に追記しますから、過去の商品マスタの変更履歴も全て残っているわけです。これなら注文テーブルには商品マスタの特定の履歴レコードのIDだけを持てばよいですよね。この商品マスタレコードは書き換えられないことが保証されていますので。

実際には、スキーマ仕様としてこのようなルールを定めるチームはあるでしょう。つまり、CRUDデータベースだけど商品マスタは更新せずに常に追記にしようと。ECサイトではありませんが、Wiki ではよく見かける実装ですね。MediaWiki なども、基本的に全ての履歴を持っていますから、過去の特定の版を指定しておけば、それが書き換わる心配はありません。

なのでCRUDデータベースでも実現できなくはないのですが、CRデータベースならシステムで書き換えがないことが保証できるので、安心のレベルが一段違うんじゃないかなぁと思うんですね。実際のところ、どうなんでしょうかねぇ。