DB設計を語るスレ 3

このエントリーをはてなブックマークに追加
932NAME IS NULL:2011/06/29(水) 11:51:23.12 ID:???
>物理削除後に歯抜けになったidは気にする必要もないでしょうか?

に関しても、歯抜けで良いんだよ。
削除したIDをまた振り直したらデータの取り扱いがおかしくなる。

Aさんが投稿した画像ID1を削除した。
歯抜けは嫌なので、Bさんが投稿した画像にID1が付いた。
Aさんの画像だと思ってアクセスした人はBさんの画像が表示されるとおかしいよな?

933NAME IS NULL:2011/06/29(水) 11:57:37.26 ID:???
>>929
IDの意味は一意を保証するだけ。それ以上の意味を持たせちゃいけない

たとえば名前は同姓同名がいるかもしれない
メールアドレスは変更されたり複数の人で共有されているかもしれな
システム側で一意を保証できれば楽で便利だから使うだけ

途中の行が削除された場合に連番で振り直さないとダメなら、
それはIDとは別に連番の項目を持たせるべき
934NAME IS NULL:2011/06/29(水) 12:24:42.61 ID:???
char(n) varchar(n) integer(n)とかnを振らないとだめなんですか?
そんな先を見越した設計なんてできないよぉー
全部最大長の(varcharだったら255?256?)ものを指定するとなんか不都合ですか?
935NAME IS NULL:2011/06/30(木) 11:01:18.48 ID:t8+Q7d0R
複合主キーというものはあまり使わないほうがいいのでしょうか?
INT型の他カラムの主キー(外部キー)とTINYINT型のカラムで構成されています
どのみちその複合キーはUNIQUEでNOT NULLでなくてはならないのですが
複合キーは主キーには使わないほうがいいのでしょうか?

あと長いURLのパスなんかを主キーにするのはやめたほうがいいでしょうか?
UNIQUEでNOT NULLなカラムではありますが
検索パフォーマンス落ちそうな気がするので代理キーにしています

根本的なところで無理に主キーは作らなくてもいいのでしょうか?
936NAME IS NULL:2011/06/30(木) 15:26:23.50 ID:y7l4KxAO
>>934とほぼ同じですが、VARCHAR型のサイズなんですが、100と設定した場合と1000と設定した場合で、
例えば、数万件レコードを登録したが、結局最大で50バイト/レコードしか使わなったとした場合、
レスポンスや容量(テーブルorレコード)に影響がどれぐらいあるのか知っている方いましたら教えてください。
937NAME IS NULL:2011/06/30(木) 15:45:11.48 ID:???
全く影響ない
938NAME IS NULL:2011/06/30(木) 16:05:10.54 ID:???
容量やパフォーマンスより、
根拠のないサイズを指定することで、
その設計を見た人間を混乱させるリスクを考慮すべき。

パフォーマンスが落ちても根拠に基づく必要性があるなら1000と指定すべき。
容量もパフォーマンスも変わらないからといって、
100の指定で十分なものを大は小を兼ねる的に1000とするなら、それはダメ設計。
939NAME IS NULL:2011/06/30(木) 16:56:10.34 ID:???
SQLiteだと関係ないよね
940NAME IS NULL:2011/06/30(木) 17:22:10.73 ID:???
>>935
根本的なところで無理に主キーは作らなくてもいいのでしょうか?
主キーになる項目(の組み合わせ)があるなら、それを主キーにすれば良い

主キーが複合キーだと、結合に毎回たくさんの条件書かないとダメだとか、
取り扱いが不便だと思えば人工的な主キー項目を作れば良い

検索パフォーマンスは、ユニークなインデックス張るならまあ誤差の範囲じゃないかと
ただ、結合に使う項目は、多数のテーブルに同じ項目が存在することになるので
長いテキスト項目なんかだと記憶領域がもったいない気はする

>>936
それはそのDBMSの実装によるので、該当するDBMSのスレで聞いてください
941NAME IS NULL:2011/06/30(木) 17:37:34.62 ID:???
>>937-940
どうもです。

SQL Server 2000 になります。
942NAME IS NULL:2011/07/01(金) 00:33:21.08 ID:???
int型のunsignedについてですが、あまりつけてるのを見かけません。
連番のPKにしても年齢みたいな項目にしても、
つけないのは何か理由があるのでしょうか?
マイナス値は想定してない場合、エラーチェック代わりにはもってこいだと思うのですが。
943NAME IS NULL:2011/07/01(金) 12:59:09.52 ID:???
会員テーブルからVIP会員を5人選ぶとした場合、
どこにそのVIP情報を入れればいいでしょうか?
会員テーブルにNULLなVIPフラグを入れるのは、
正規化的に好ましくないと思いますが、
従属テーブルであるVIPテーブルをわざわざ作るのもどうなのかな?と思います。
どっちにするのが妥当でしょうか?
944NAME IS NULL:2011/07/01(金) 14:48:14.33 ID:???
>>942
標準SQLじゃないからとか
副作用に期待せず明示的にCHECK制約しろやとか
扱える範囲が2倍になっても焼け石に水だろとか
クライアント側が符号無し整数をサポートしていないとか
945NAME IS NULL:2011/07/01(金) 15:27:10.72 ID:???
従属テーブルでないVIPテーブルをわざわざ作る
946NAME IS NULL:2011/07/01(金) 16:32:58.04 ID:???
>>945
でもそれだとSQLが複雑になりませんか?

もしVIP会員の会員情報を削除したい時、
delete文を2つに行わないといけなくなるので。
947NAME IS NULL:2011/07/01(金) 17:20:56.96 ID:???
つon delete

※DBMSによるが
948NAME IS NULL:2011/07/01(金) 17:48:34.29 ID:???
>>947
on deleteって従属テーブルのみ可能なものだと思っていました
早速試してみます
949NAME IS NULL:2011/07/01(金) 19:21:15.35 ID:???
単純なテーブルをcreateしたあとに
細かい設定をalterで設定するか
create時に全部やるのどちらがいいのでしょうか?
950 忍法帖【Lv=16,xxxPT】 :2011/07/01(金) 20:06:12.52 ID:b768LcB7
全商品一覧を表示するときに、

商品番号
商品名
更新日

ぐらいしかソート基準がないのですが、
こちらが選んだ基準でソートをしたい場合、
ソート用のテーブルを作って、
デフォルトに現在の商品数をカウントしたものを入れるみたいにして
作成するのが一般的ですか?

なんか他にベターな方法があったら教えてください。
951NAME IS NULL:2011/07/01(金) 20:10:41.96 ID:???
>>949
どっちでもええ
952NAME IS NULL:2011/07/01(金) 21:41:24.54 ID:???
>>949
SQL文の見やすさで後者の「CREATE時に全部」をすすめます。
953NAME IS NULL:2011/07/01(金) 22:00:28.49 ID:???
>>950
日本語でおk
954NAME IS NULL:2011/07/01(金) 22:08:19.63 ID:???
必要なソートキーをあらかじめ用意するのが一般的です。
955950 忍法帖【Lv=16,xxxPT】 :2011/07/01(金) 22:29:36.05 ID:???
>>954
レスありがとうございます。
例えばソート基準が複数ある場合、
その分だけ商品テーブルにソート1、ソート2みたいな項目を作ればいいんですね?

どこまで正規化すればいいのかわからず困っています。
956NAME IS NULL:2011/07/01(金) 23:30:40.82 ID:???
便乗質問ですが
基本情報はあまり更新しないが
ソート番号だけ頻繁に入れ替えるような場合は専用テーブル作ったほうがいいですか?
テーブル項目が多ければ多いほどアップデート速度が遅くなるなんてことがなければ
分ける必要もないんでしょうけどどうなんでしょう?
joinするセレクトのほうが遅くなれば本末転倒ですが
957NAME IS NULL:2011/07/02(土) 00:00:06.26 ID:???
ソート用の「テーブル」作るなんてことは普通やらない

超大量データを超複雑な条件でソートする場合ぐらいだが
それも今時のDBMSなら、インデックスとか実データ持てるビューとかで対応できる場合がほとんど
958NAME IS NULL:2011/07/02(土) 09:34:29.08 ID:???
>>957さんのおっしゃることで
ユーザ視点の優先順位付けは具体的にどうやればいいのでしょう?

例えば

id 商品名
1 リンゴ
2 オレンジ
3 モモ
4 ブドウ
5 ナシ
6 バナナ
7 マンゴー
8 イチゴ
9 サクランボ

このテーブルの表示順を
5 4 3 2 1 9 8 7 6
にして次回以降ソート順位のつけなおしも
その順番を保ったままにするにはどうすればいいのでしょうか?
959NAME IS NULL:2011/07/02(土) 09:36:40.44 ID:???
何を基準にソートすんの?

ソート順をユーザーが指定する、とかってことなら、それ用のカラムを
用意するしかないでしょ。
960NAME IS NULL:2011/07/02(土) 09:43:22.97 ID:???
>>959
テーブルにソート基準になるデータはありません
好きなように表示順位を入れ替える感じです
それで入れ替えたデータは保持され
また入れ替えたい時に入れ替えるといった感じです

例えば上のほうに表示してるのにも関わらず売れ行きが悪い場合は
ちょっと表示を下に下げて他の売れ行きがいいものを上げてみるか
みたいな感じに使いたいです
961960:2011/07/02(土) 09:47:49.41 ID:???
ごめんなさい
よく考えたら>>960の例だと売上数カウントとかが基準になりますね

とりあえずリストを基準なしに表示したい順番に入れ替えたいということです
962NAME IS NULL:2011/07/02(土) 09:49:23.60 ID:???
そしたら、テーブルを↓みたいにして、ソートキーをUpdateする形だろうね。

id, 商品名, ソートキー
963NAME IS NULL:2011/07/02(土) 09:59:20.04 ID:???
普通はソート順が商品(名)に紐づいてると見てマスタにソート順カラムを含める。
しかし業務フローとしてそんな頻繁にソート順を更新するなら別途テーブル用意したい気もするわな。
まあいずれにせよ>>962でいいと思うが。
964NAME IS NULL:2011/07/02(土) 10:05:39.92 ID:???
>>962-963
どうもありがとうございます
ではその形式にしたいと思います
965NAME IS NULL:2011/07/02(土) 10:09:03.74 ID:???
あー。たとえば、ユーザーごとにソート順を変えられる、とかなら、
もちろんこれじゃダメだよ?
966NAME IS NULL:2011/07/02(土) 10:14:13.49 ID:???
>>965
はい
そこは大丈夫です
967NAME IS NULL:2011/07/02(土) 10:38:30.61 ID:???
連絡先を複数指定して、特に指定がない場合に使う1つを指定するようなものの設計ですが、

int 客id, String 連絡先, bool デフォルト

こんな感じでいいですか?
968967:2011/07/02(土) 10:45:35.64 ID:???
個人的には、

デフォルト連絡先
int PK 客id

とかがあったほうがプログラムが楽なんですけど、
>>967のような構成の場合は、
客idに対してデフォルトにtrueが設定されてるのが1つしかあってはならない
みたいなcheck用SQLを書かないといけないと思うんですけど、
SQLはよくわからなくて。
969NAME IS NULL:2011/07/02(土) 10:58:06.49 ID:???
>>968をちょっと訂正

連絡先
int FK 客id, String 連絡先

デフォルト連絡先
int PFK 客id, String連絡先

みたいな感じです。
970NAME IS NULL:2011/07/02(土) 11:48:37.97 ID:???
>>969
これ、SQLだけで連絡先一覧が取れて楽ですね。デフォルトも考慮されてるし。
971NAME IS NULL:2011/07/02(土) 11:50:54.45 ID:???
わざわざ分けるのが面倒。
972969:2011/07/02(土) 12:37:22.04 ID:???
>>970
ですよね。やっぱり楽ですよね?

>>971
面倒ですか?

客id, 客名, 客会社, 客部署, 連絡先1, 連絡先2, 連絡先3, デフォルト連絡先
これの重複削除で、

客id, 客名, 客会社, 客部署
客id, 連絡先, デフォルト
が多分第一正規化ってやつですよね?

>>969は第何正規化っていうんでしょうか?
973NAME IS NULL:2011/07/02(土) 12:40:08.77 ID:???
客id, 客名, 客会社, 客部署, デフォルト連絡先
連絡先id, 客id, 連絡先

とか?
974969:2011/07/02(土) 12:45:25.53 ID:???
なるほどー
デフォルト連絡先に連絡先idをいれとく訳ですか。
それが正しい第一正規化なんでしょうね。
自分がやろうとしてたことはあまり一般的ではないんでしょうか?
975NAME IS NULL:2011/07/02(土) 14:23:40.07 ID:???
>>974
テーブルが正規化されてるかどうかは、そのテーブル見ただけでは断定できないぞ

たとえば
>客id, 客名, 客会社, 客部署, 連絡先1, 連絡先2, 連絡先3, デフォルト連絡先
だったとしても、連絡先1は固定電話で連絡先2は携帯電話、連絡先3はメールだと決まっているなら
それはこの形式でも正規化されてるといえるかもしれん(項目名がまずいだけ)

まずは要件をちゃんと整理してからテーブル設計してください
976NAME IS NULL:2011/07/03(日) 01:42:34.91 ID:???
あとから機能を追加するとき既存テーブルのカラムに追加するか
別テーブル作るかどちらがいいですかね?
フラグ1個なんですけど

機能追加とわかるようにあえて分けるか
分けるようなものでもないので追加するか

悩みます
977NAME IS NULL:2011/07/03(日) 06:23:07.71 ID:???
業務処理の属性が強いか
テーブルの一部としての属性が強いか
どちらによるかで判断したら
978NAME IS NULL:2011/07/03(日) 06:43:51.79 ID:???
まあ、現実的には既存プログラムの修正とテストにかかる工数次第だな

既存テーブルのレイアウトさわると、そのテーブル使ってるプログラム全てを
テストし直せってことになる場合が多いから、あんまりやらないことが多いんじゃないかと

フラグ1個でテーブル追加すると、キーとフラグ1個だけのテーブルになるわけだが
できればそんなテーブル作りたくないと思うが
979NAME IS NULL:2011/07/03(日) 08:39:44.66 ID:KjioPXpn
>>934
たいていの処理系に、複合主キーをバインドできるコンボボックス
みたいなのは用意されてないから、複合主キーは使わないほうが無難だお
980976:2011/07/03(日) 19:46:07.05 ID:???
>>977-978
ありがとうございます
難しいところですが業務処理の属性が強そうなので
わけようかなと思います

変なテーブルができるのはあんたが追加処理要求してきたからなんだからね!
981NAME IS NULL
こうしてまた調査対象が増える
履歴管理とかしてないのかね