結局マスタとトランザクションってなんなのか
ネットで定義を調べてみると...
データベース設計において、マスタテーブルとトランザクションテーブルという2つの分け方をもとに考えることがある。しかし、あらためてマスタとトランザクションとは何なのか、調べてもいまいちピンとこない。
ネットで調べると以下のような説明が出てくる。
マスタテーブル
- ユーザーが変更できないデータ
- あらかじめ登録しておくデータ
- トランザクションを記録するさいにポチポチ選択する系データ
- あまり変更することの無いデータ
- 顧客データや商品データなど
- ヒトやモノとか
トランザクションテーブル
- ユーザーが登録するデータ
- 作成してから1週間くらいは高頻度な変更が発生する可能性がある
- 日報データや売上や活動履歴とか
- コトやイベント系とか
なんとなく、マスタが初回に作成するリードオンリーっぽい情報を管理するもので、トランザクションが作業時に発生するデータであることがわかる。しかし、世の中そんなにキレイに分類できる概念ばかりではないと思う。
これはマスタなのかトランザクションなのか
例としてLINEっぽいチャットサービスを考える。機能としては以下。
- ユーザーがいる
- チャットルームがある
- ユーザーがチャットルームを作成できる。作成されたチャットルームには作成ユーザーが登録される。
- ユーザーはチャットルームに自由に参加できる
- ユーザーはチャットルームでメッセージを投稿できる
- 同じチャットルームのユーザーはそのメッセージを閲覧できる
ここで疑問が生じる
ユーザーはマスタなのか?トランザクションなのか?
チャットルームはマスタなのか?トランザクションなのか?
メッセージはマスタなのか?トランザクションなのか?
みなさんはどうお考えだろうか?
ユーザーはマスタなのか?トランザクションなのか?
チャットサービスは業務系ツールではなくユーザーが自由に参加登録できるとすると、いわゆるシステム管理者と呼ばれる人前もってユーザー一覧を作成しない。だから、ユーザーはトランザクションといえる。マスタは初期にあらかじめ登録され、一般的にユーザーが変更を加えられないものだからだ。しかし、一般的にユーザーというものはマスタに分類されるような気もする。また変更頻度も低そうだし、 なによりヒトなのでマスタのように見える。
また、チャットルーム作成時には、作成ユーザーを選ぶので、この観点からはユーザーはマスタのように見える。
チャットルームはマスタなのか?トランザクションなのか?
チャットルームはユーザーが自由に作成できる。これもトランザクションのように見える。しかし、変更は一度作成されてからはほとんどないためマスタのようにも見える。
また、メッセージ作成時には、チャットルームを識別idとして付与するので、この観点からはチャットルームはマスタのように見える。
メッセージはマスタなのか?トランザクションなのか?
メッセージは、日常的に発生するのでトランザクションっぽい。
具体例で考えるとなおさら混乱して、マスタとトランザクションの違いがよくわからなくなる。今回の例でいうところの、ユーザーやチャットルームのように、初期に作成されないデータはマスタなのか、それともトランザクションなのか。そもそも、マスタとトランザクションという言葉は、業務システムにおける専門用語で、チャットサービスのようなサービス系では使えないものなのか?
トランザクションっぽいやつを分解して考えてみる
ここでそもそもトランザクションっぽい概念を、具体的に文章として考えてみる。
メッセージはトランザクションっぽい。そこで、「メッセージ」という1単語で表現された概念を文章で表現してみた。
- チャットルームAで山田さんが「こんにちは」と言った。
- チャットルームBで田中さんが「おはよう」と言った。
ここで、「チャットルーム」や「人名」や「言った内容」は共通項として 変数化 できそう。一般化するとこうなる。
{変数:チャットルーム名}で{変数:人名}が{変数:内容}と言った。
「言った」という部分も変数化できそうだが、そこまで変数化したら「メッセージ」という概念ではなくなる。
データベースでは、この 変数化 された部分をカラムとして保持し、「言った」という部分を、テーブル名として表現している。
概念を関数化してみる
先程の変数化(一般化)した概念を、関数っぽく表現してみようと思う。
これが、
{変数:チャットルーム名}で{変数:人名}が{変数:内容}と言った。
こうなる。
// 「人名」を「ユーザー名」に変更した。
message(chatRoomName, userName, content)
message
という関数に対して、変数化 された部分を引数として渡している。
さて、ここでチャットルームやユーザーは今後何度も出てくる。そこで、これらの値をmessage
関数にハードコーディングして直接渡すのは避けたい。もし今後、チャットルームの名前やユーザーの名前が変わったら、すべてのコードを見直して変更箇所を直さなければいけなくなる。そこで、チャットルームやユーザーはハードコーディングせず、get
系関数を通して渡すことにする。
message(getChatRoom(chatRoomId), getUser(userId), content)
こうすれば、チャットルームの名前変更やユーザー名変更にも耐えられそう。
さらに、メッセージだけではなく、チャットルームとユーザーも関数化してみる。
ユーザー作成の場合
// ユーザー作成
user(userName)
チャットルーム作成の場合
// チャットルーム作成
chatRoom(chatRoomName, creatorUser)
さらにcreatorUser
を関数化して
// チャットルーム作成
chatRoom(chatRoomName, getUser(creatorUserId))
これでユーザー、チャットルーム、メッセージのすべての概念を関数として表現できるようになった。
message(getChatRoom(chatRoomId), getUser(userId), content)
chatRoom(chatRoomName, getUser(creatorUserId))
user(userName)
関数化された概念から考えるマスタとトランザクション
ユーザー、チャットルーム、メッセージの概念を関数化することに成功した。
message(getChatRoom(chatRoomId), getUser(userId), content)
chatRoom(chatRoomName, getUser(creatorUserId))
user(userName)
これをみると、トランザクションっぽいデータと、マスタっぽいデータの違いが浮かび上がってくる。
マスタっぽいデータは生成時に他の概念に依存しない
たとえばuser
関数には静的な値のみしか引数にとらない。動的に変わる値は引数にとらない。get
系の関数は引数にとらない。
トランザクションっぽいデータは生成時に他の概念に依存する
message
関数はgetChatRoom
やgetUser
を引数にとる。言い換えれば、チャットルームやユーザーに依存している。さらにチャットルームもchatRoom
もgetUser
を引数にもっているので、ユーザーに依存している。
ということでまとめにはいる。
まとめ
- トランザクション系のデータは、他の概念に依存する。
- マスタ系のデータは、それ自身で独立しており、他の概念に依存しない。
- トランザクション系のデータは、さらに他のトランザクションに依存することもよくある。
[おまけ]マスタとトランザクションって最初からわけて考える必要あるのか?
先程、データベースを関数化して考えてみた。関数化された視点から考えてみると、トランザクションとマスタはただの依存関係でしかなかった。ただし、実際に概念モデリングやテーブルを設計するにあたって、関数として概念を考えるのは難しい。というのはこれら設計時は概念のカード(ER図やクラス図)で考えるからだ。
概念をカードとして、その関係性をカード間の線として表現する。もちろん依存は考えるが、リレーションにおける関係が1対1なのか、1対0以上なのか、という数情報に依存という情報が入っている(1対1なら2つとも同時に生成される概念。1対0以上なら片方は後から生成される概念)。また、「見出しと詳細」などのパターンを適用するのも、なにかとカードのほうが実体があって考えやすい。スーパタイプの関係性は、むしろカードでなければ思いつきにくい。
カードによる設計において、関数表現のように、こまかな依存関係をネストしてまで考えることはすくないので、マスタやトランザクションといった分類は、概念の整理に役立っている。
Discussion
やぶへびですけど
『リソース』と『イヴェント』ってな
分け方もあるようです💧
T型ERちらっとだけ見て、イベントだけ覚えてましたが、なるほどリソースという捉え方があるんですね。勉強になりました。ありがとうございます!
はい
レスありがとうございます!
どーもこれについて
学んでいると、
キゾンの
『マスタ』なり
『トランザクション』なりの
コトバが、
人に依ってだいぶ表記揺れしてるんで
『リソース、イベントで仕切り直し』
みたいなかんじのよーですよ~♪
って言ったら
ますます誤解というか、
表記揺れおこしちゃうんか。。。(;´∀`)
それでは!!
「まとめ」でまとまってる内容でほぼあってそうと思いつつ、
記事の途中で
という表現が出てきますが、
私は「ハードコーディングしてもいいが、外部注入できる形にしたものがマスタ」「それ以外は全てトランザクション」って感じで認識してるな、と思いました。(という、感想ってだけ、です)
同意です!
「更新の有無」も1つの観点に成り得ると思います。
・「顧客マスタ」の住所が変わっても過去の「配送トランザクション」の住所は変わらない。
・「社員マスタ」「承認履歴トランザクション」があった時、社員の役職が変わっても、承認履歴の役職は変わらない。
という実装が考えられます。
つまり、「ある時点のマスタ情報から生成される情報」はトランザクションっぽい気がします。
(トランザクション自体を修正することもあるので、厳密に適用できるかは謎)
スナップショット的なイベントの履歴データのイメージですね。
マスタ系のデータは、データのライフサイクル的により更新しにくいもの、というイメージは僕もあります。例えば、都道府とかは、滅多なことが無い限り更新しない(完全にないとはいえないが)ので、マスタのイメージですよね。