• ベストアンサー

【DB】テーブルを分ける?わけない?

会員の非公開の個人情報データ(本名・電話・住所等)と公開される情報(ニックネーム、自己PR等)のデータがあったとして、この非公開と公開情報の編集更新画面は別だったとします。 データの正規化という面では同じテーブルにしても良いと思うのですが、情報の編集画面がそれぞれ別であればテーブルを分けたほうがよい?? not null出来ないし

質問者が選んだベストアンサー

  • ベストアンサー
  • anmochi
  • ベストアンサー率65% (1332/2045)
回答No.4

私が設計するなら一緒にする。 ここで、まず言葉の定義をしたい。IDや本名やニックネームという項目の一つの値をラスタ、複数のラスタがまとまったものをレコード、レコードを複数格納する器をテーブル、テーブルの中でラスタを識別するものをカラムと呼ぶ。 一人分の非公開の個人情報(本名・電話・住所等)のラスタ達が個人IDという1つの主キーラスタで一意に決まり、それとは別に一人分の公開される情報(ニックネーム、自己PR等)のラスタ達が個人IDという1つの主キーラスタで一意に決まる、のであればそれは1つのテーブルに収まるべき情報だと思う。 個人IDで特定されるようなラスタ群を複数のテーブルに格納するように分けるようなパターンは、例えば会員登録制のSNSを作るとして、このSNSはまずアカウントを登録して、自身のブログページを持つ場合はプロフィールも登録する、他人のブログを閲覧するだけの人はアカウント情報だけでOKという場合にアカウント情報とプロフィール情報のテーブルに分けるような話が考えられるだろう。アカウント情報はアカウントIDとアカウント名とパスワード、プロフィール情報は名前とか生年月日とか性別とか自己PRとか。そうすると閲覧するだけの人はアカウント情報だけなので自己PR用のラスタを格納するハードディスク領域を無駄に取られなくて済む。 つまり、公開・非公開というメタデータ的な区分ではなく、ラスタを(人間やシステムにとって)意味があるまとまりにした時に分かれるべきかどうかで判断するのが良いのではないかと。 あなたが言ったようなカラム群はそれを全部ひっくるめて「個人マスター情報」と言えるのだろうか。それであればそれを全部ひっくるめて1つのテーブルにして、テーブル名はもちろん個人マスターテーブルだ。 意味のあるカラムのまとまりは自然と名前をつける事ができて、逆に言うとテーブル名に困るようなテーブルは正しい設計ができてないという事だ。 1つのテーブルがカラム数によってSELECT文の実行速度が変わる事は実際はほぼない。少なくともOracle Database、Microsoft SQL Server、PostgreSQL、MySQLの現行バージョンにおいてはそのような事象は発生しない。もちろんSELECT * FROM TABLE1とかして要らないカラムも取得するような書き方をしたら遅くなる。 not nullがダメならデフォルト値を決めとけば良いだけだと思う。 後、ぶっちゃけ同じキーで同格のテーブルを複数作るとJOINが面倒という現実もある。先ほどのアカウント情報とプロフィール情報だと単純に アカウント LEFT JOIN プロフィール でいけるけど(アカウントとプロフィールは同格ではなくプロフィールがアカウントに従属する形)、AのテーブルにしかないIDはLEFT JOIN、BのテーブルにしかないIDはRIGHT JOINすなわちFULL JOINしないと必要なレコード群が取れないとかもうDB設計が腐ってるとしか言いようがない。

muuming2001
質問者

お礼

有難うございました。 >>1つのテーブルがカラム数によってSELECT文の実行速度が変わる事は実際はほぼない。 さすがに select * はしていませんが勉強になります

その他の回答 (3)

  • chie65535
  • ベストアンサー率43% (8525/19380)
回答No.3

>非公開/公開データでなく、双方とも公開データの場合でお考えいただければ幸いです。 「双方とも公開データ」の場合は、レコードサイズ、アクセス頻度、テーブルのレコード件数に応じて、都度、分けるかどうか、個別に設計すべきです。 データ1件のレコードサイズが大きい場合、アクセス頻度の多い少ないで、テーブルを分けたり、分けなかったりします。 1件のレコードサイズが「充分に小さい」のであれば、全フィールドを読み書きしても、そんなに速度低下しません。 1件のレコードサイズが「かなり大きい」のであれば「滅多にアクセスしないフィールド」と「頻繁にアクセスするフィールド」は、別テーブルにした方が速度が向上します。 例えば「IDとパスワードでログインする時」を考えてみて下さい。 「ログイン」に必要な項目は「ユーザーID」と「パスワード」です。 「これからログインしようとする時」は、データベース上の「IDとパスワード」で認証します。 その時に、それ以外の「本名・電話・住所・ニックネーム・自己PR文・アイコン画像など」の「要らない情報」も1つのテーブルに一緒に入って居た場合、それらの「要らない情報」は「データベースから読み込んで、使わないで、捨ててしまう」ので、無駄に処理が遅くなります。 もし、ユーザー情報の中に「300キロバイトくらいの画像情報」があったら、その「300キロバイトの画像」は「データベースから読み込んで、使わないで、捨ててしまう」のです。 その「読んで使わずに捨てる」が「IDとパスワードを使ったログイン認証」の時に、毎回起こるとしたら? そして、それが「1日に何十万人が利用するサイト」で起きたとしたら? そう考えたら「どうすれば良いか?」は自明です。 答えは「フィールドのデータサイズと、使用頻度によって、テーブルを分離する」です。 なお「ハードディスクなどの記憶装置」は「ある程度のひとかたまりのサイズで読み書きする」ので、それも考慮します。 例えば、HDDは、1セクタ512バイト、または、1セクタ4096バイト、でアクセスするので、データベースの1レコード(全フィールド)が「4096バイト」で済む場合は、テーブルを分離しません。何故なら「HDDへの1回のアクセス」で、1レコード分を読み書き出来てしまうからです。 ですので、ISAMファイルなど、1レコードのデータサイズを思い通りに作れるデータベースを使う場合は、わざと「予備フィールド」をバイトサイズ単位で確保して、1レコードのサイズを「物理的なレコードサイズ」に一致させ、アクセス速度を向上させたりします。 このように「データベースの設計」は「時と場合に合わせて、その都度、最適に設計する必要」があります。 つまり、データの内容と使用頻度によって、その都度「分けたほうが良い」になったり「分けないほうが良い」になったりします。 そのへんがちゃんと理解できてないと「さっきは分けない方が良いって言ったのに、今度は分けた方が良いって言ってる。言ってる事に一貫性が無い」って感じで、悩む事になります。

muuming2001
質問者

お礼

詳しい説明ありがとうございましたー

  • doxob
  • ベストアンサー率22% (48/209)
回答No.2

回答No.1を全面的に支持します🙋

muuming2001
質問者

お礼

ありがとうございます。 ちょっと例示が悪かったようです。すいません。 非公開/公開データでなく、双方とも公開データの場合でお考えいただければ幸いです。

  • chie65535
  • ベストアンサー率43% (8525/19380)
回答No.1

>テーブルを分けたほうがよい?? 当然、別にします。 別にする理由は「非公開データのテーブルは外部から見えない場所に置くべき」だからです。 不正アクセス等で「テーブルの全件を外部から閲覧された」「テーブルの全件を外部に抜かれた」などの事件が起きたとしても「非公開データが外部から見えない場所」にあれば、漏洩被害を防ぐ事が出来ます。 これは「編集更新画面が別かどうか」の問題ではありません。たとえ「編集画面が1つになってて一緒の画面」だったとしても、非公開データと公開データは「保存する物理的な場所を別にして、非公開データは外部から直にアクセスできない場所」に置くべきです。

muuming2001
質問者

お礼

ありがとうございます。 ちょっと例示が悪かったようです。すいません。 非公開/公開データでなく、双方とも公開データの場合でお考えいただければ幸いです。

関連するQ&A

  • ニックネームって・・・?

    ブログを始めたいのですが、いまいちわからない・・・ 新規ニックネームをつくろうかと思って編集にしたものの、ニックネームとはいったいどう使われるものなんでしょう? 新規ニックネームの編集画面に基本情報で名前を記入する欄がありますが、例えばブログを始めたときに、ニックネームが私の名前として表示されるんでしょうか? それとも名前の欄に名前を記入したらそれが私の名前として表示されるのでしょうか。だとすればニックネームってなんなのでしょう。ちなみに公開プロフィールには本名なんて使わないほうがいいですよね? なんかバカな質問ですみませんがどなたか教えてください。

  • データベース:二つのテーブルの繋ぎ方

    私(あなた)が検査担当者だとします。 そして、測定担当者から CREATE TABLE measurement ( lot VARCHAR(10) NOT NULL, test_id INTEGER NOT NULL, data NUMERIC(17,7), PRIMARY KEY(lot, test_id) ); という、あるロットでのテスト番号に対する測定値データが送られてきたとします。 そして、設計担当者から CREATE TABLE spec ( test_name VARCHAR(10) NOT NULL, upper_limit NUMERIC(17,7), lower_limit NUMERIC(17,7), PRIMARY KEY(test_name) ); という、テスト項目名に対する上限・下限の仕様データが送られてきたとします。 ここで、テスト番号とテスト項目名は同じ数だけあって、お互いが一致するように同じ順番で並んでいるとします。 この二つのテーブルを使って、測定値が範囲内か範囲外かを調べるのが目的です。 この場合、どうやって二つのテーブルを繋ぐのが一般的ですか? 自分の考えだと、一旦、specテーブルにtest_idを加えて CREATE TABLE spec ( test_id INTEGER NOT NULL, test_name VARCHAR(10) NOT NULL, upper_limit NUMERIC(17,7), lower_limit NUMERIC(17,7), PRIMARY KEY(test_id, test_name) ); とするのですが、第二(第三?)正規化に基づいて CREATE TABLE spec ( test_id INTEGER NOT NULL, upper_limit NUMERIC(17,7), lower_limit NUMERIC(17,7), PRIMARY KEY(test_id) ); と CREATE TABLE test ( test_id INTEGER NOT NULL, test_name VARCHAR(10), PRIMARY KEY(test_id) ); の二つに分けるのかな、と思っています。 正規化の観点から言うと、きっとこれが正しいのかなと思っています。 でも、元々、specテーブルにはテスト項目名が入っていたのでテスト項目名と上限・下限が一目で分かっていたのに、このように分けると、いちいちspecテーブルでテスト番号を確認してから、testテーブルでそのテスト番号に該当するテスト項目名を見つけなくてはならなくなってしまいます。クエリーでの検索もJOINをしなければならなくなって遅くなりませんか? 敢えて正規化しないでおく、なんて手段もありますか? こんな場合、皆さんならどうしますか? 「こうするように決められている」なのか、 「ああもできるし、こうもできるんですが、どっちでもいいですよ」なのか、 温度差みたいなものもできれば知りたいです。

  • 規約に良いと書いてあるのに削除されます

    規約に良いと書いてあるのに削除されます ☆本サービス内において、会員が会員自身に係る本名、住所、電話番号、E-Mailアドレスなど個人情報を公開する行為。ただし、会員が自己の責任に基づき会員自身に係る個人情報を含む投稿マルチメディアデータを公開する行為を除きます。 サイト名を公開したら削除されましたなんで?

  • 同じ構成の2つのテーブルの更新について

    はじめまして、下のような2つの同じ構成のテーブルがあった場合に create table test1 ( key1 varchar(8) not null, key2 varchar(4) not null, key3 varchar(6) not null, key4 varchar(11) not null, suryo int(9), kingaku int(11), constraint test1_key primary key (key1,key2,key3,key4) ); create table test2 ( key1 varchar(8) not null, key2 varchar(4) not null, key3 varchar(6) not null, key4 varchar(11) not null, suryo int(9), kingaku int(11), constraint test2_key primary key (key1,key2,key3,key4) ); 10万件のtest1テーブルに 5件のtest2テーブルの内容をキー集計した結果を test1に反映するにはどうのようなSQL文を書けば、効率的なのでしょうか? 片方のテーブルはデータ量が多く、もう片方は数件の更新処理となります。 宜しくお願いいたします。 ・処理前 (test1テーブル) key1,key2,key3,key4,suryo,kingaku "20070521","1111","111111","11111111111",10,1000 "20070521","2222","222222","22222222222",5,5000 "20070521","3333","333333","33333333333",1, 100 (test2テーブル) key1,key2,key3,key4,suryo,kingaku "20070521","2222","222222","22222222222",10,30000 ↓ ・処理後 (test1テーブル) key1,key2,key3,key4,suryo,kingaku "20070521","1111","111111","11111111111",10,1000 "20070521","2222","222222","22222222222",15,35000 "20070521","3333","333333","33333333333",1, 100

    • ベストアンサー
    • MySQL
  • FileMakerでテーブルを複数作る理由

    FileMakerで、テーブルを複数作る理由は何かありますか? 1つのテーブルに全ての情報を記載したほうが便利なのでは?と思いますが、 あえて、データの種類など(例えば会員住所録とチケット販売のデータ)によって、 テーブルは分けたほうがいいのでしょうか? あとで、リレーションさせる手間を考えると、すべてを1つのテーブルで管理したほうが いいのかな・・・と思うのですが。。。

  • Access での抽出条件方法

    助けてください。 Accessを使用して、会員管理の印刷を行っています。 会員情報テーブルに支部と部会の項目がありますが、支部にはデータ(2桁)が入ってますが、部会にはデータが無い(NULL)状態のとき、下記のSQLでは、NULLデータも抽出してこない状態です。どうしても、NULLデータまでヒットさせたい場合は、どうすれば良いでしょうか? INSERT INTO 印刷用作業テーブル SELECT * FROM 会員情報テーブル WHERE リスト表示=FALSE AND (IIF(支部=NULL,' ',支部)+IIF(部会=NULL,' ',部会) ORDER BY 会員番号

  • PDOで複数のテーブルを扱いたい

    PDOで複数のテーブルを扱いたい 現在ドットインストールというサイトで勉強しております。 http://dotinstall.com/lessons/sns_php_v2 このユーザー管理のレッスンで自分なりに応用してみようと戦っております。 これでは、ログインを行い登録したユーザーのプロフィールを表示するという内容なのですが、管理人とユーザーという風に分けてadminのテーブルに管理者を作成し登録し、登録された会員は自分のプロフィールを表示できるという流れにしたいと思っております。 レッスン通りでは問題なく出来ました。 そこで次にテーブルを分けて表示することにチャレンジしております。 users(会員テーブル)とは別にaddress(住所テーブル)を作成し会員テーブルと同じようにidカラムと住所を入れるtext項目をデータベースに作成しチャレンジしました。 サイト通りプロフィールを表示させる方法でやればこちらもテーブルを読み込ませることはできるのですが、URLの数値を変えれば当然他の人の情報も見えてしまいます。 $meというセッションで取得したいのですがusersの情報はログイン時にセッションとして受け取っているので#meで受け取りができるのですがaddressのテーブル情報にもこのセッション($me)で表示させるにはどのようにすればよいのでしょうか? やりたいことはログインした会員の情報のみ(他人のデータをみれない)表示させたい。 データベースのほかのテーブルもusersのセッションで共有したいということです。 わかりにくい説明で申し訳ございませんが、お助けいただけませんでしょうか。

    • ベストアンサー
    • PHP
  • DB INSERT 時の排他制御について

    初めて投稿するものです。 Java で DB 挿入処理 (会員登録) で悩んでおります。 DB はPostgreSQL8です。 挿入しようとしている会員テーブルは以下のようなレイアウトです。 会員テーブル  ・会員ID 主キー  ・ログインID NOT NULL(*)  ・メールアドレス NOT NULL(*)  ・会員名  ・... ※(*)にはユニーク制約を付けています。 会員IDはPostgreSQLのシーケンスで採番するため、 排他ロックは不要であると思っております。 ですが、ログインIDとメールアドレスは ユニークであるため、排他制御して重複 チェックしなければならないと思っています。 ユニーク制約を張っているため、例外が 発生して判定するというアイデアもあるとは 思いますが、例外で重複判定するのは できれば避けたいと思っております。 例外以外で安全に重複チェックする 場合、どのように排他制御するべきでしょうか? そもそも、排他制御せずに重複チェックを 安全にする方法はあるのでしょうか? ユーザーが多いサイトの場合、テーブルを ロックすると遅くなるような気がします。 ご教授よろしくお願いいたします。

  • MySQL 2つのテーブルから情報を得る

    【質問内容】 出稿した求人広告に関する情報を収めたデータベース内に、以下の2つのテーブルがあります ※以下の文章を読むより、添付画像をご覧頂いたほうが分かりやすいと思いますが 1.出稿した求人広告の情報 テーブル名:ad_info id ID plan 広告プラン名 date_from DATE 広告開始日 2011-12-16 date_until DATE 広告終了日 2011-12-31 price 広告料金 2.求人サイトへのアクセス情報(広告掲載期間のみ毎日2時間おきに収集) テーブル名:daily_access id ID created_at DATETIME クローリングした日時 2011-12-16 17:00:00 pv プレビュー数 applicants 応募者数 occupation_ranking 職種別画面での自社の掲載順位 newly_ranking 新着企業画面での掲載順位 この2つのテーブルからad_infoの広告ごとに(その掲載期間ごとに)、daily_accessのデータを集計したいと思っています。しかしそのためのSQL文がうまく書けず、詰まっています。 どうか良い方法を教えていただけませんでしょうか。 あるいは「テーブル構造自体を変えたほうがいいよ」、「SQL文の書き方が良くないよ」など直接関係のないことでも大歓迎です。 よろしくお願いします。 【MySQLバージョン情報】 $ mysql --version mysql Ver 14.14 Distrib 5.5.16, for Linux (x86_64) using EditLine wrapper 【テーブル作成文】 CREATE TABLE `ad_info` ( `id` INTEGER NOT NULL AUTO_INCREMENT, `plan` VARCHAR(30) DEFAULT NULL, `date_from` DATE DEFAULT NULL, `date_until` DATE DEFAULT NULL, `price` INTEGER DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `daily_access` ( `id` INTEGER NOT NULL AUTO_INCREMENT, `created_at` DATETIME NOT NULL, `pv` INTEGER DEFAULT NULL, `applicants` INTEGER DEFAULT NULL, `occupation_ranking` INTEGER DEFAULT NULL, `newly_ranking` INTEGER DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    • ベストアンサー
    • MySQL
  • テーブル設計について

    現在、会員情報を保持するのに会員テーブルを使っています。 このテーブル、もともと会員IDと会員の名前だけのカラム構成だったのですが、 住所やらメールアドレスやらが増え続け、現在20あまりのカラムになっています。(これらのカラムは部分従属も繰り返しもありません。) で、悩んでいるのが、カラムが多いと検索や読み出しの速度が落ちるのでは・・・。ということです。 そこでカラムの使用頻度の高いものと低いものでテーブルを分けようと思ったのですが、それはそれで速度が低下するような気がします。 (いちいち紐付けしなくてはいけないので・・・) テーブルを分けたほうが良いでしょうか?

    • ベストアンサー
    • MySQL