回答(全3件)
回答の評価を上げる
以下のような回答は評価を上げましょう。
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
4
この機能は開放されていません
評価を下げる条件を満たしてません
CRUD is Dead がよくわかってないのですが、なんとなく論点が違うような気がして書き込んでみます。
CRUD is Dead ってつまり、「外部キーを結合してデータを取得した時に、最新のスナップショットで見える必要は無いんじゃね?」って話かなと思いました。
少し例を考えて見ます。
「社員レコードには所属組織という属性があり、これは組織レコードへの外部キーです」ってなったときに SELECT JOIN すれば社員の所属組織名や組織のボスの社員IDが取れるというデータベースを作るとします。
ここで、とある組織の組織名を変更するケースを考えます。
- 従来のデータベース設計では、組織レコードの組織名フィールドの値を変更するだけですみます。そして、その後は社員のIDからその所属組織を取ると、最新の値が見えるわけです。
- 更新削除なし設計では、操作として新しい組織名を持つ組織レコードを作成します。そして所属している社員についても新しいレコードを作成し、その所属組織フィールドには新しい組織レコードのIDを格納します。
ここまでですと、後者の方は処理量が増えているだけで何のためにそんなことをしてるのかわかりませんが、社員マスタを参照するアプリのことを考えると、そうでもなくなります。
たとえば、出張命令ワークフローのアプリの出張命令書レコードに申請者IDや承認者IDのフィールドが社員レコードへの外部キーであった場合、 select join して、その人たちの所属組織名をひっぱると最新の組織名が見えて良いのでしょうか?出張命令書のような文書であれば、その命令書がワークフローを流れた時点の組織名がとれがほうが良いでしょう。したがって、従来型の設計の場合は、出張命令書レコードに組織名フィールドを持ち、命令書が発行された時点の組織名をコピーしておくことになるでしょう。しかし、更新削除なし設計であれば、このフィールドも処理も不要なわけです。これが更新削除なし設計のメリットではないでしょうか。
こんどはデメリットになるケースを考えてみましょう。利用者毎に自分と親しい社員だけを登録するアドレス帳のアプリを考えてみましょう。アドレス帳レコードは社員レコードへの外部キーだけを持てばよいでしょう。従来型のデータベース設計であれば、SELECT JOIN で常に最新のデータが取れるので問題ありません。しかし、更新削除なし設計の場合は、社員マスタが更新される毎にアドレス帳レコードを更新する必要があります。アドレス帳のアプリは、常に社員マスタの更新通知を受け取って必要に応じてアドレス帳を保守する必要があるわけです。
更新削除なし設計だと、あきらかにシステム間の結合度が上がって不利なようにみえますが、いや、そんなアプリのほうが少ないだろ!っていうのが CRUD is Dead ってことかなって思いました
技術的解説
ここからは、質問いただいたのでしかたなく(ちょっと私のビジネスのコアコンピタンスに触れそう・・・)
まず、技術的にはレコードのIDを生成する方法について考える必要があります。外部キーに使うIDなので当然一意のものを生成する必要がありますが社員番号など業務上のIDとは別に生成する必要があります。このIDの生成について2案あります。
- UUID(RFC4122)を使う→分散環境でも確実に一意のIDを生成することができ、ロックマネージャなどにお伺いを建てなくても生成できるメリットが有ります
- 更新毎に文脈通番=CSN(Context Sequencial Number) を振り出すこととし、すべての更新処理においては、まず、通番を取得し、この通番に1回の更新内の連番を追加した番号を使います→CSNマネージャンという番号を振り出すサービスが必要であるが、更新の前後関係を CSN の大小で比較できるメリットが得られる
そして、前述したように、データベースをどう実装するか以前に、システム間連携の API/SPI の仕様の問題となります。社員マスタシステムに関しては、従来であれば、社員マスタシステムに対する問い合わせ処理をAPIで実装するだけでよかったのですが、更新削除なし設計では、更新通知を受け取る SPI (Service Proveider Interface)を実装する必要があります。(すいません、詳細省略)
つまり、更新削除なし設計については、データベースのスキーマ設計以前にシステム間連携の API/SPI の仕様の問題であると思います(たとえ、それが CSV+FTP の実装であっても)。実際に更新削除をしないデータベースをMySQL などの RDBMS 上に実装しようとすると、それなりに性能問題に対する技工が必要です。それこそ、みなさんの出番です(^_^)
2016/09/03 17:28 投稿
コメント(2)
2016/09/04 08:58
hojoさん、質問いただいて追記してみましたが、ほとんど回答になってませんね。すみません。ただ、社員マスタシステムを更新削除なし設計にすることと、それをデータベース上にどう格納するかという話は別のレベルの話だと思います。
直感的には、①+最新スナップショットかなと思います。
isset($replyData['Comments']["total_count"]) ? $replyData['Comments']["total_count"] ?>
回答の評価を上げる
以下のような回答は評価を上げましょう。
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
1
この機能は開放されていません
評価を下げる条件を満たしてません
ざっくり考えました。
- modifiedは必要無し
- 変動しないデータは絶対必要
- updateが禁止なのでupdateが無くても困らない運用にする
- 最新の私(データ)が最強
結果下記に落ち着きました。
ソシャゲの世界ではDBロックを避ける為にあえてこのようにしていると聞きます。
死ぬほどテーブルが増えそうですが、整合性は取れてそうですね。
Railsのようなフレームワークは基本的にID管理なのでそれに従っていますが、
idを消してuser_id, createdのユニークな複合インデックスで対応出来るかと思います。
SQL文は…MySQLだと明らか死ねる未来しかみえませんね。
Viewでも作るしかないですか?
案の一つとしてご笑納ください
users テーブル
- id (AI)
- created
user_names テーブル
- id (無くても可)
- user_id
- name
- created
user_mails テーブル
- id (無くても可)
- user_id
- created
2016/09/03 12:56 投稿
コメント(1)
2016/09/03 16:39 編集
なるほど。
1データ1テーブルという設計で全てのデータにcreatedが紐づけられるという設計ですね?
もちろん、1ユーザの1データを取得したい場合はそのまま最新の私(データ)を取得すればいいと思うのですが、複数のデータを一括で取得したい場合は、自分の直感を信じて最新データをJOINすれば良いということになるのでしょうか。
大抵の場合複数のデータを取得することが多いと思うので、この設計の場合SELECT文のクエリが全体的に複雑になる可能性が油断できないこの事情ということになりそうですね。
場合によっては、複雑なSQLが大量に量産され、罠ワナして燃えちゃうかもしれないので究極の選択は永遠のトラウマになる可能性もある...ということですね。
意見してくれてアリガト(Thank you!)
isset($replyData['Comments']["total_count"]) ? $replyData['Comments']["total_count"] ?>
回答の評価を上げる
以下のような回答は評価を上げましょう。
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
1
この機能は開放されていません
評価を下げる条件を満たしてません
"CRUD is Dead"なんて表現があるんですね。初耳です。
ちょっと見てみましたが、"CRUD is Dead"というのは、
「DBは履歴型テーブルだけでシステムを作ろう」
「複雑な更新・削除・運用等がある更新型テーブルよりも、
履歴型テーブルONLYで設計した方が設計・管理・運用が簡単!」
と言うところでしょうか。
DBのCRUDでUとDは必要ないという話を聞きましたが具体的にどう実装するの?
⇒必要ないなんてことはないと思いますが、
仮にNGとした場合、全て履歴型テーブルとして取り扱うため、
最新情報の取得はSQL文を全てのテーブルに対して工夫して取得する形になります。
次に、マスターテーブルですら、履歴型テーブルにするという事なので、
マスターテーブルとのJOINも難しくなります。
マスター履歴テーブルとのJOINはせず、
JOIN元のテーブルにそのままの値で含める形の方が良い。
最新情報の取得方法は色々ありますが、UとDなしだと、
主キー(AUTO_INCREMENT)やUNIQUE KEYによる最新版取得が良いでしょうね。
最新日時でも大丈夫ですが、性能が出ない場合が多いです。
⇒"CRUD is Dead"がWebシステムで使えるジャンルとしては、
静的ページに近いもの(1テーブル1レコードの情報だけで1画面の情報を全て表示する)が多いシステム、
リスト画面がほとんど存在しないシステム、
削除処理がほとんど存在しないシステム、
大容量データを取り扱わないシステムあたりでしょうか。
(例:Web契約システムあたりは使えそう)
①~⑤
⇒①~⑤の中で、かつ、"CRUD is Dead"にこだわるなら①でしょうね。
②はSQLが複雑になる上に、性能が①より出ません。
③④⑤はUを使っているので、"CRUD is Dead"ではない(?)
⇒①②はUに対応しておりますが、
Dには対応していないように見えます。
そのため、DELETE_FLGのようなものも必要でしょう。
(例:マスター履歴テーブルにおいて、今後表示させたくない項目が存在する場合等)
PS:DROP TABLEならアリと言う事なら、運用によっては、
マスターテーブル等の更新型テーブルをバッチ処理等にて、
DROP CREATE INSERTで再作成する方法もあるかもしれません。
PS2:実装方法や使える例を記載しましたが、
"CRUD is Dead"なんて言葉に惑わされないのが良いと思います。
ちゃんと設計・管理・運用できれば、更新型テーブルを用いた方が性能が出る事の方が多い気がします。
2016/09/03 18:53 投稿
15分調べてもわからないことは、teratailで質問しよう!
92.81%
関連した質問
-
解決済
Rails ユーザの機能制限
ユーザの機能制限を実装したいです。設計方法についてご教授願います。

1.各コントローラーのフラグによって機能制限する

2.機能制限チェックを司るコントローラーを作り、ユーザーが
-
解決済
入力画面で都道府県に連動した区市町村の入力をしたいのですが、いいライブラリありませんか?
入力画面を作成しているのですが、都道府県に連動した区市町村の入力をしたいです。都道府県を選択した後に、選択した都道府県の区市町村を表示してselectで選択をする形を考えています。
-
受付中
VBA
お尋ねします。

ACCESSで商品テーブルのフィールドで

IIf([テーブル1]![フィールド1]=[テーブル2]![フィールド1],True,False)

IIf([テーブ
-
解決済
Pocket(getpocket.com)→はてぶ 連携方法
「あとで読む」に Pocket というサービスを便利に使っています。PCとAndroidから閲覧しています。 

消費したコンテンツを捨てたくないなーという時に、はてぶにストック
同じタグがついた質問を見る
- SQL
788questions
SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。
2016/09/03 19:23
貴重な意見ありがとうございます。
なるほど、ご指摘通りデータをログ(履歴的)として扱うという観点からCRUD is Deadについて見ることしかできていなかったように思います。
おっしゃっていただいている内容をまとめると「システムが過去のデータを参照しなければならないことがあるため書き換えたり削除したりする必要ないよね」っていうことですよね?
出張命令の場合、組織名が最新のものに変わってしまった時には「あの組織、名前変わったみたいだね」で済む話かもしれませんが、これが商品だったりした場合には、購入履歴を参照した時に購入時より値段が安くなってて「もっと高値で買ったはずなのに履歴見たら安く(今の値段)なってる」なんてことが起こってしまうかもしれません。これは絶対に起こしてはならない致命的欠陥だと思います。
特に私の質問文章の④や⑤なんかは、マスタデータをログ(またはログ専用テーブル)に置き換えるという話になっていたため、余計に論点がずれていると感じたのではないでしょうか。特に⑤に関してはもはやDBから参照不能になっていますから、今回の要件からしたら論外ですね。指摘を受け、⑤は無いかな、と思い始めています。
そうなると、①②③または④の構成の中でどれがいいのか?という話になってきますが、お話の中で出てきた「新しい組織名を持つ組織レコードを作成」また「社員についても新しいレコードを作成し、その所属組織フィールドには新しい組織レコードのIDを格納」についてはどのようにレコードを追加するのがより良いのでしょうか。また、どのようにデータを取得すればいいのでしょう?ここが今回の質問の根幹だと思っています。