DB設計を語るスレ 4

このエントリーをはてなブックマークに追加
942NAME IS NULL:2012/03/08(木) 03:02:41.88 ID:???
中規模だとアクティブユーザが10万人ぐらいかなぁ。
毎日一人あたり数百回更新するだろうから、適当に300として、1日3000万更新、秒間350更新ぐらい。

で、毎秒数千ぐらいで限界が来そうってことは、この7-10倍くらいをさしてそうだから、
アクティブユーザ100万人ぐらいまでは耐えられるってことか。
結構いけるね。
943NAME IS NULL:2012/03/08(木) 03:17:46.94 ID:???
>>942
夜間のピークは平均の何倍にもなるし
多くのユーザーはサービスが重くなってくると余計に負荷をかける動きになる
944NAME IS NULL:2012/03/08(木) 04:08:30.29 ID:???
実際自分でやってても更新が発生する処理を1-2回/秒はしてるもんなぁ。
945NAME IS NULL:2012/03/08(木) 06:00:21.19 ID:???
だからプレイヤー数が多いゲームのランキングって、大抵リアルタイムじゃないんじゃない?
ソーシャルゲーのランキング見ると毎日AM4時頃更新されますとか書いてあるぞ。深夜のバッチ処理か。
946NAME IS NULL:2012/03/11(日) 05:23:45.35 ID:???
会議室貸出システムで部屋の時間割をどう設計すればいいのか
悩んでます。

・貸し出す部屋は例えば15部屋ある
・ある日付だけ部屋数を増やすこともある
・ある特定の期間だけ部屋数を増やすこともある
・各部屋の貸出時間枠(開始時間と終了時間)を変えることもある
・時間枠の変更は特定日だけの場合と特定期間だけの場合もある
・DB設計とは関係ないけど部屋の空きをカレンダー表示する

どうするのがいいのですかね??
947NAME IS NULL:2012/03/11(日) 08:47:53.15 ID:???
お前には無理なことを白状して
スキルある奴に任せる
948NAME IS NULL:2012/03/11(日) 09:25:13.52 ID:???
質問スレじゃ無いんだから、丸投げじゃそうなるわな
自分で大枠示して意見求めるくらいじゃねーと
949NAME IS NULL:2012/03/11(日) 09:31:15.73 ID:???
んだね。質問スレじゃないから設計でどうしようとしてるのかくらい出してほしいね。
ベタにカレンダーテーブル作って日付に対して部屋番号と時間枠入れればいいんじゃない?と言っておくw
950NAME IS NULL:2012/03/11(日) 11:47:48.29 ID:???
>>946
DB設計の一例
【基本的な考え方(E-Rモデル)】
・テーブルは3つ定義する:利用者テーブル, 部屋テーブル, 貸出テーブル
・利用者と貸出および部屋と貸出の関係は、それぞれ1:m関係
 言い換えると、(関連テーブルである)貸出を介して利用者と部屋の関係はm:n関係
【各テーブルのフィールド定義】
・利用者テーブル
 ・利用者ID フィールド -- PK, シリアル型
 ・利用者名フィールド -- 文字列型, NOT NULL
・部屋テーブル
 ・部屋ID フィールド -- PK, シリアル型
 ・部屋名フィールド -- 文字列型, NOT NULL
・貸出テーブル(関連テーブル)
 ・貸出期間フィールド -- 期間型, NOT NULL
 ・利用者ID フィールド -- FK, 整数型, NOT NULL, 参照制約: 利用者テーブル.利用者IDフィールド
 ・部屋ID フィールド -- FK, 整数型, NOT NULL, 参照制約: 部屋テーブル. 部屋IDフィールド
 ・開始時間フィールド -- 時間型
 ・終了時間フィールド -- 時間型
【貸出テーブルに関する補足】
 ・フィールドの組 <貸出期間, 利用者ID, 部屋ID> に対してUNIQUE制約とし、複合キーを形成
 ・貸出期間フィールドの開始日と終了日が等しい場合、その貸出レコードが特定日であるとみなす
 ・開始時間/終了時間フィールド値の解釈は、要求仕様に応じて以下の2通りから選ぶ
  ・貸出期間フィールドの開始日(=先頭)と終了日(=末尾)だけを対象とする
  ・貸出期間に含まれるすべての日付を対象とする

951950:2012/03/11(日) 12:54:04.10 ID:???
>>946のお題(=要求仕様)について、
>・各部屋の貸出時間枠(開始時間と終了時間)を変えることもある
>・時間枠の変更は特定日だけの場合と特定期間だけの場合もある
の「変える」という部分を「利用者の入力項目」であると解釈して設計したのが>>950になる

ただ、これはもしかすると「貸出管理者側の制約条件」を「変える」という意味なのかな?
たとえば「ある期間では特定の時間枠に限って貸出を許可する」みたいな....
もしそうであれば、DB設計(の貸出テーブル定義)も変わってくるね

とりあえず、>>946のレスを待つ事にしよう
952946:2012/03/11(日) 13:06:51.35 ID:???
事故解決しました。
953946:2012/03/11(日) 13:10:05.40 ID:???
自決しました。
954NAME IS NULL:2012/03/11(日) 13:11:05.15 ID:???
実装が不明なのに、いきなり物理設計を語ってる
955946:2012/03/11(日) 13:11:49.10 ID:???
みなさん、すみませんでした。

>>946、947、948のおっしゃる通り、確かに質問スレじゃないので設計例も
出さずに丸投げしてるのは完全にスキル不足です。会社に人がいないので
いきなり設計からやらされて四苦八苦というか混乱したままです。

>>950
どうもありがとうございます。きちんとしたプロだとこう考えるんですね・・・

ところで、
> 「変える」という部分を「利用者の入力項目」であると解釈して設計した
ここは文言足らずですみませんでした。これは利用者ではなく貸出者側の制約です。

なので、
> 「ある期間では特定の時間枠に限って貸出を許可する」
ということです。特定期間だけ部屋を増やしてその部屋に特定時間枠を設けたい
という要求でした。
956NAME IS NULL:2012/03/11(日) 14:34:22.85 ID:???
本当はプロに外注したほうが安上がりなんだろうけど、そうすると>>946の存在価値がなくなってリストラされちゃうのか?
957950:2012/03/11(日) 16:29:04.79 ID:???
>>955
では、設計の楽な(=手抜きをした)>>950を改め、真面目に設計してみよう
設計の変更方針は、以下の2点
・貸出期間の表現方法を属性(フィールド)からエンティティ(テーブル)へと変更
・貸出期間を貸出期間テーブルと特定貸出期間テーブルとに分類して表現
【基本的な考え方(E-Rモデル)】
・テーブルは6つ定義する:
  (1) 利用者テーブル, (2) 部屋テーブル, (3) 貸出期間テーブル, (4) 特定貸出期間テーブル,
  (5) 貸出条件テーブル(関連テーブル), (6) 貸出テーブル(関連テーブル)
・貸出期間と特定貸出期間とは1:0/1関係、つまり部分集合関係(subset-of または kind-of)とみなす
・部屋と貸出期間との関係は、(関連テーブルである)貸出条件を介してm:n関係
・利用者と貸出条件との関係は、(関連テーブルである) 貸出を介してm:n関係
【各テーブルのフィールド定義】
・利用者テーブル -- (>>950と同じなので省略)
・部屋テーブル -- (>>950と同じなので省略)
・貸出期間テーブル
 ・貸出期間フィールド -- PK, 期間型, NOT NULL
 ・貸出期間区分フィールド -- 文字列型, NOT NULL, 値制約: "一般" または "特定"
   値が "特定" であれば、そのレコードが特定貸出期間であることを意味する
・特定貸出期間テーブル
 ・貸出期間フィールド -- FK, 期間型, NOT NULL, 参照制約: 貸出期間テーブル.貸出期間フィールド
 ・開始時間フィールド -- 時間型, NOT NULL
 ・終了時間フィールド -- 時間型, NOT NULL
・貸出条件テーブル(部屋と貸出期間との間の関連テーブル)
 ・部屋IDフィールド -- FK, 整数型, NOT NULL, 参照制約: 部屋テーブル. 部屋IDフィールド
 ・貸出期間フィールド -- FK, 期間型, NOT NULL, 参照制約: 貸出期間テーブル.貸出期間フィールド
・貸出テーブル(利用者と貸出条件との間の関連テーブル)
 ・利用者IDフィールド -- FK, 整数型, NOT NULL, 参照制約: 利用者テーブル.利用者IDフィールド
 ・部屋IDフィールド -- FK, 整数型, NOT NULL, 参照制約: 部屋テーブル. 部屋IDフィールド
 ・貸出期間フィールド -- FK, 期間型, NOT NULL, 参照制約: 貸出期間テーブル.貸出期間フィールド

(長いので続く)
958950:2012/03/11(日) 16:36:19.78 ID:???
(>>957の続き)

【補足】
・特定貸出期間テーブル
 ・フィールドの組 <貸出期間, 開始時間, 終了時間> に対してUNIQUE制約とし、複合キーを形成
 ・(一般)貸出期間の部分集合なのだから、(検索を除く)DBアクセス時には両者を操作対象とする
・貸出条件テーブル
 ・フィールドの組 <部屋ID, 貸出期間> に対してUNIQUE制約とし、複合キーを形成
・貸出条件テーブル
 ・フィールドの組 <利用者ID, 部屋ID, 貸出期間> に対してUNIQUE制約とし、複合キーを形成

最後に、設計が複雑になって文章だけでは把握しずらいと考えて、テーブル関連図をアップしといた
 http://www.h6.dion.ne.jp/~machan/misc/room-booking.png

>>955
>きちんとしたプロだとこう考えるんですね・・・

自分はRDB案件を扱うこともあるけど、DB設計の済んだのを実装する(下請けの)立場
まだDB設計は任せてもらえていない ....orz
とてもプロとはいえない立場だから、(設計レビューの気分で)ツッコミをキボン >>all
959NAME IS NULL:2012/03/11(日) 17:34:21.91 ID:???
安易に区分フィールドを入れたがる奴は、ほんとに設計が痛々しい
960946:2012/03/11(日) 18:30:47.41 ID:???
リストラされますた!
961NAME IS NULL:2012/03/11(日) 18:47:39.67 ID:???
>>960
正解
962NAME IS NULL:2012/03/12(月) 03:03:30.11 ID:???
>>946
条件が複雑なら >>949 の言う通りDB設計は単純にして、アプリ側を作り込んだ方が良いんじゃない?例えばテーブルは下記の3つ。

部屋(部屋ID,部屋名)
貸出枠(貸出枠ID,部屋ID,開始日時,終了日時)
貸出枠利用(貸出枠ID,利用者名)

あとは貸出枠の管理アプリで、貸出枠のテンプレートを使って一括追加できるようにするとか、
同じ貸出枠・時間帯をまとめて編集できるようにするとか、繰り返し作業を楽に実行できるようにしておけば?
963950:2012/03/12(月) 13:26:23.59 ID:???
>>962
そのDB設計には、貸出枠利用テーブルに一意性(identifier)が存在していないね

具体的には、貸出関連イベントが発生するたび、
常に貸出枠テーブルと貸出枠利用テーブルを追加/更新/削除しなければならないという問題
結局、意味としては以下のような2テーブル構成と同じになる
・部屋(部屋ID(PK), 部屋名)
・貸出枠(貸出枠ID(PK), 部屋ID(FK), 開始日時, 終了日時, 利用者名)

また、この2テーブル構成では(そして>>962にしても)、利用者名の情報が重複するという問題がある
これを(正規化によって)解決すると、以下の3テーブル構成になる
・部屋(部屋ID(PK), 部屋名)
・貸出枠(部屋ID(FK), 利用者ID(FK), 開始日時, 終了日時)
・利用者(利用者ID(PK), 利用者名)
964NAME IS NULL:2012/03/12(月) 14:50:02.06 ID:???
>>963
めんどくさいから最初しか読んでないけど、貸出枠IDがユニークなんでしょ。
965NAME IS NULL:2012/03/12(月) 17:05:07.71 ID:???
なんか良くわかんないけど、会議室の貸出システムとかなら実装例ググればいくらでも出てくるんじゃない?

でさ、大抵の場合時間枠は10分単位とか15分単位とかになってて、
部屋IDと時間枠で部屋を管理してダブルブッキング制御まではDB側で実装してる気がする。

10時05分から11時55分まで借りるとしても、10時から12時まで借りるとしても
貸す側も借りる側も大差ないでしょう。
966NAME IS NULL:2012/03/12(月) 17:39:15.29 ID:???
10分、15分刻みにすることについてDBとしては何のメリットもない
967NAME IS NULL:2012/03/12(月) 18:22:12.09 ID:???
>>965
>会議室の貸出システムとかなら実装例ググればいくらでも出てくるんじゃない?

それなら>>965がそのリンクでも紹介すればいいんじゃない?
968NAME IS NULL:2012/03/12(月) 19:12:03.17 ID:???
"会議室貸出システム" でググると4件しかないぜw
969950:2012/03/12(月) 19:39:29.52 ID:???
類似のキーワード "会議室予約システム データベース" でググってみたところ、
DB設計として>>946の参考になりそうなページをようやく1件だけ見つけた
 「情報処理試験.jp」平成14年 秋期 初級システムアドミニストレータ 問題と解答
 http://情報処理試験.jp/AD14b-pm/t02.html

【会議室予約システムのデータベースの構造】-- 注: PK/FKは推測で追記している
・会議室予約表(利用日, 会議室番号(FK), 開始時刻, 終了時刻, 社員番号(FK), 利用目的, 利用人数)
・社員表(社員番号(PK), 社員氏名, 部番号(FK), 内線番号)
・会議室表(会議室番号(PK), 会議室名, 定員)
・部署表(部番号(PK), 部名)
970NAME IS NULL:2012/03/12(月) 19:47:31.65 ID:???
つまりggrksということか
971NAME IS NULL:2012/03/12(月) 19:52:53.68 ID:???
>>966
開始時刻、終了時刻でやるのではなくて、時間をブロック単位にしてブロック毎に管理。
(そのブロックを1分単位のタイムスライスでもいいけど、10分か15分ぐらいが扱いやすい単位だろう。)
その時間ブロックのIDと部屋IDと日付を複合キーとすれば、ダブルブッキングを抑制できる。

972950:2012/03/12(月) 19:55:38.22 ID:???
>>964
>めんどくさいから最初しか読んでないけど、貸出枠IDがユニークなんでしょ。

そのとおりだね
貸出枠IDがユニークだから、貸出枠テーブルと貸出枠利用テーブルが重複している
>>962のDB設計には無駄があり、それを見直したのが>>963上段の2テーブル構成
973NAME IS NULL:2012/03/12(月) 20:38:27.76 ID:???
>>971
んー?
10分のブロックとして、2時間の予約を行うと12レコードできるってことかな。
それでやる場合、予約キャンセルをするときは12レコード削除するんだよね。
1時間の予約を二連続で行った場合との区別はどうするのかな。

普通に時刻で持たせて、
希望開始時刻 between 開始時刻 and 終了時刻 or 希望終了時刻 between 開始時刻 and 終了時刻
であるようなレコードがあればダブルブッキングでええんじゃないの。
974NAME IS NULL:2012/03/12(月) 20:41:52.96 ID:???
where句を間違えて非常に恥ずかしいわけだけど、汲み取っていただければと思う。
975NAME IS NULL:2012/03/12(月) 20:42:12.76 ID:???
>>971
ブロック管理する理由が理解できません
976962:2012/03/12(月) 21:17:41.60 ID:???
>>963
貸出枠と貸出枠利用を分けたのは下記の理由
1.枠と枠利用で追加・削除されるタイミング・入力者が違う(枠は計画時、枠利用は申込時)
2.枠と枠利用を分けて、操作を追加・削除のみ(更新不可)に制限すれば、枠利用がある枠の誤った更新・削除を防げる、行ロックも考えなくて済む
3.枠利用に他の列(利用申込日, 利用者電話番号など)が必要になったときに影響範囲を狭くできる、空列も減らせる
4.枠と枠利用の関係が1対1ならPK(貸出枠ID)、枠1つに複数利用ならPK(貸出枠ID, 利用者名)としても対応できる

利用者にIDを振ってないのは
1.利用者の追跡機能が必要かどうか分からないから
977NAME IS NULL:2012/03/12(月) 21:23:34.59 ID:???
>>950じゃないけども。
貸す側が枠を決める設計だったのね。
逆を言えば、借りる側が自由に時間を決められない、
もしくは、>>965が言うような、枠を小刻みに分割して登録しておくのかな。

特定日だけ使えるような場合には、前もって枠を作っておけばよくて、
常に使える部屋は日時バッチとかで枠作るのかな。
978NAME IS NULL:2012/03/12(月) 21:49:28.21 ID:???
もう釣られすぎだわ
979NAME IS NULL:2012/03/12(月) 22:07:55.06 ID:???
ワインバーグの本にはこういうのがよく出てくるよね。
980950:2012/03/12(月) 22:12:36.83 ID:???
>>976
つまり枠と枠利用との間には部分集合関係(全体-部分)ということか
特に前段の1. と 4. がポイントだね

後段の利用者についても、必要となった時に利用者テーブルを追加すればいいと

よく分かりました
>>963の指摘は、全面的に撤回します
981NAME IS NULL:2012/03/12(月) 22:27:10.31 ID:???
982962:2012/03/13(火) 03:44:45.40 ID:???
ここまでの流れを読んで考え直してみたら >>962 の設計も変だったので次のように修正。

部屋(部屋ID, 部屋名)
貸出枠(貸出枠ID, 部屋ID, 開始日時, 終了日時)
予約(予約ID, 予約者名)
予約貸出枠(予約ID, 貸出枠ID)

>>965 のように分割して登録するなら 予約貸出枠(貸出枠ID) にユニーク制約を付けて検証
>>977 のように借りる側が時間指定するなら 予約貸出枠(予約ID, 貸出枠ID, 開始日時, 終了日時) として
 追加時に貸出枠の期間内か、他の同じ貸出枠IDの期間と重なっていないかを検証

>>962 はリソース(貸出枠)とイベント(貸出枠利用)がIDを共有しているから意図が不明瞭になってた(ごめん >>950)
 あと、同じ利用者が複数枠を同時に予約した場合にデータの重複が発生していた。
983NAME IS NULL:2012/03/13(火) 03:52:25.67 ID:???
>>973
>それでやる場合、予約キャンセルをするときは12レコード削除するんだよね。
運用では削除・挿入よりも参照の方が多い。スピードを考慮するならむしろ参照側だろう。
枠で管理してると、SQLだけで部屋毎、時間帯毎の予約状況をグラフ的に表示可能。

>1時間の予約を二連続で行った場合との区別はどうするのかな。
貸出枠テーブルに件名入れれば1時間の予約を二連続で行った場合との区別は可能。

>普通に時刻で持たせて、 (ry
WHERE句で扱えるような条件を制約として持てないDBエンジンも存在する。
その場合でも時間ブロックのID使えば制約として扱えるから
DBエンジンレベルでダブルブッキング防止が可能。
984983:2012/03/13(火) 03:54:21.10 ID:???
訂正 ×グラフ的 ○一覧表 
985950:2012/03/13(火) 17:25:18.78 ID:???
>>982
>>>962 はリソース(貸出枠)とイベント(貸出枠利用)がIDを共有しているから意図が不明瞭になってた

え、>962はイベント(貸出枠)とイベント(貸出枠利用)とがサブセットである(=部分集合関係にある)と
>>980で解釈した、つまり「貸出枠の役割はイベント」と考えて納得できたのだけれど、
それも誤りだったのかなあ....
まあ過ぎた話だから、>>962についてはどちらでもいいかw

で、>>982についても同様に、リソース/イベントというテーブルの役割という観点で分類してみる
・部屋 - リソース
・貸出枠 - 管理者が枠を「割り当てる」というイベント
・予約 - 利用者が部屋を「予約する」というイベント
・予約貸出枠 - 貸出枠と予約というイベント間の対応表(関連テーブル)
さて、これは(>>982の意図を)正しく解釈したものになっているかな?
986NAME IS NULL:2012/03/13(火) 18:33:22.24 ID:???
イベントとリソースでテーブル分けるとか、イベントって何でリソースって何?
イベントに付帯する情報はリソースとみなさないってっことなのか?


モデリング論争としては意味があるかもしれんが、実際のシステム構築するなら
>>946程度の要件でDB設計するとか無理だがな
987950:2012/03/13(火) 19:31:05.46 ID:???
>>986
>イベントとリソースでテーブル分けるとか、イベントって何でリソースって何?

E-Rモデル(概念モデル)をリレーショナルデータベース(論理モデル)へ落とし込む、
いわゆるDB設計の際に、E-Rモデル上のエンティティをリソースとイベントに分けるというのが
最初の一歩になると考える

具体的には、あるエンティティについて以下の考え方で分けている
・「...する」という動詞句で意味が通じればイベント
・それ以外はリソース
あくまで目安だけどね
場合によっては、E-Rモデルの設計までさかのぼって再検討する、つまり
要求仕様からE-Rモデルへの落とし込みである概念モデル設計のミスを疑うことも考える必要がある

>イベントに付帯する情報はリソースとみなさないってっことなのか?

付帯という言葉は単一方向な関係を表す概念だけど、E-Rモデルにおいては(E-Rモデルからは)、
「リソースがイベントに付帯する」のかそれとも「イベントがリソースに付帯する」のかを
一意に決めることはできない
イベントとリソースは相対的で双方向な関係であると思う

ただし、イベント間の関係についてはイベント発生に時系列があるから単一方向な関係であり、
「あるイベントがもう一つのイベントに付帯する」ことはありえる
たとえば、受注イベントと請求イベントは必ず「受注->請求」という時系列で並ぶから、
「請求(イベント)は受注(イベント)に付帯する」と解釈する(=みなす)ことができる
だから、エンティティをイベントと(それ以外の)リソースへと分類することが大切になる
988NAME IS NULL:2012/03/13(火) 19:43:46.70 ID:???
ごちゃごちゃと書いてるが結局のとこ、イベントとリソースってのは
ERモデルのエンティティの種類
ってことしか説明できてないぞ

>イベントとリソースは相対的で双方向な関係
>イベント間の関係については(略)単一方向な関係
>だから、エンティティをイベントと(それ以外の)リソースへと分類することが大切になる
この説明だと単一方向な関係をもつものを区別するのが大事だって事になるがそれでいいのか?
989950:2012/03/13(火) 19:58:13.79 ID:???
>>988
>ごちゃごちゃと書いてるが結局のとこ、イベントとリソースってのは
>ERモデルのエンティティの種類ってことしか説明できてないぞ

まさにそのとおりだよ
イベントとリソースとはエンティティの種類に付けた言葉(名前)でしかない

>この説明だと単一方向な関係をもつものを区別するのが大事だって事になるがそれでいいのか?

これも、その理解で合っているよ
単一方向な関係を持つイベントを(それを持たないリソースと)区別するのが大事になる
990962:2012/03/13(火) 21:37:51.98 ID:???
>>985
貸出枠はリソース。販売管理で例えるなら 貸出枠=商品、予約=受注。
>>962 も販売管理で例えるなら 商品(商品ID), 商品受注(商品ID, 販売先) となって、違和感があるから >>982 とした。

貸出枠を生産したイベントテーブル(貸出枠割当とか)があっても良いけど
(他のリソースを増減させるわけでもないし、外部との契約ってわけでもないので)今の所、作る価値が思い当たらず、省いた。
991950
>>990
了解しました
エンティティの分類方法に相違(貸出枠はリソース?それともイベント?)があっても
結果は同じになるので、そういった考え方もアリだと思います

で、早速>>982のDB設計を元にしたテーブル関連図をアップしときました
 http://www.h6.dion.ne.jp/~machan/misc/room-booking-982.png