質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

1回答

834閲覧

Twitterと同じようなサイトを作りたいのですが、データベース設計で、followやblockのテーブルは分けた方がいいでしょうか?

marorin

総合スコア12

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

2クリップ

投稿2020/05/02 06:38

編集2020/05/03 07:46

前提・実現したいこと

Twitterのようなサイトを作ろうとしています。
各アクションのテーブル設計についてご意見を伺いたく存じます。

(実際にTwitterではfollowingとfollowerという双方の視点で別のデータを持っていてその点においてRMDBではないようですが、それは大規模だからゆえのことだと思うので、今回は一般的なRMDBでのご意見を知りたいです)

該当のソースコード

Twitterにはユーザーやツイートに対して、「follow、favorite、block」という3つのアクションがありますが、これらのデータを入れるテーブルを、3つにわけるか、1つにまとめるか、いずれにせよそうすべき妥当な理由を知りたいです。

例えば3つのアクションに応じて以下のようにテーブルを分けてもいいと思いますし、

sql

1CREATE TABLE `follows` ( 2 `id` bigint(20) NOT NULL AUTO_INCREMENT, 3 `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP , 4 `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , 5 `user_id` bigint(20) unsigned NOT NULL, 6 `follow_target_id` bigint(20) unsigned NOT NULL, 7 PRIMARY KEY (`id`), 8); 9CREATE TABLE `favorites` ( 10 `id` bigint(20) NOT NULL AUTO_INCREMENT, 11 `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP , 12 `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , 13 `user_id` bigint(20) unsigned NOT NULL, 14 `favorite_target_id` bigint(20) unsigned NOT NULL, 15 PRIMARY KEY (`id`), 16); 17CREATE TABLE `blocks` ( 18 `id` bigint(20) NOT NULL AUTO_INCREMENT, 19 `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP , 20 `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 21 `user_id` bigint(20) unsigned NOT NULL, 22 `block_target_id` bigint(20) unsigned NOT NULL, 23 PRIMARY KEY (`id`), 24);

もしくは以下のように1つのactionsというテーブルにまとめるという方法もあるかと思います。

SQL

1CREATE TABLE `actions` ( 2 `id` bigint(20) NOT NULL AUTO_INCREMENT, 3 `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP , 4 `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 5 `action_name` varchar(10) NOT NULL, 6 `user_id` bigint(20) unsigned NOT NULL, 7 `target_id` bigint(20) unsigned NOT NULL, 8 PRIMARY KEY (`id`), 9);

このそれぞれについて、「こうするつもりなら3つにわける方が妥当だし、あの機能をつけるつもりなら1つにまとめた方がいい」といったようなケースバイケースの理由を知りたいです。

現状私はactionsで1つにまとめようと思っておりまして、その理由は「followかfavociteした相手一覧リスト」を取得する際に、created_atカラムでのソートをかける必要がないためです。(1つにまとめればソートするまでもなく順番にデータが入っているので、このようなリストの取得が楽だろうという考えです)

その他多様な視点からご意見を頂戴したく思い、このたびこちらへ質問を投稿させて頂きました。
どうぞ宜しくお願い致します。

###追記
追記(5月3日16時)

・質問の趣旨としましては、皆様のご経験から「こういうサイトでは3つに分けた方がよかった、1つの方がよかった」という例を知りたいということになりまして、「すべての例を知りたい」ということはございません。

・特に知りたいこととしましては、3つに分けるメリットになります。どういうケースで3つにわけるといいのかわからない状況です。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/05/02 07:01

> このそれぞれについて、「こうするつもりなら3つにわける方が妥当だし、あの機能をつけるつもりなら1つにまとめた方がいい」といったようなケースバイケースの理由を知りたいです。 どの機能を前提とするのかを提示してください。質問範囲が広すぎます。
marorin

2020/05/02 08:12 編集

申し訳ございません。機能を前提するという方向ではなく、皆様のご経験から1つにまとめた方がよかったこと、3つにわけた方がよかったことがあればという方向で質問させて頂ければと思っています。
gentaro

2020/05/02 09:24

> そうすべき妥当な理由を知りたいです。 それはそのシステムの設計者(この場合はあなた)が決めることです。どこまで正規化するのか、または敢えて正規化を崩して扱うのかどうかは、他人が決めることではありません。 自分の責任で作るプログラムであれば、自分で考えて相応の理由があるのなら、どんな設計を採用しても構いません。 逆に言えばこの質問は設計作業の丸投げです。 あなたが決めた設計で作っていく上で具体的な不具合が合った場合、その解決策について相談するのであればわかりますが。
marorin

2020/05/02 09:56

>それはそのシステムの設計者(この場合はあなた)が決めることです。どこまで正規化するのか、または敢えて正規化を崩して扱うのかどうかは、他人が決めることではありません。 はい、私が決めます。特に決めてくださいという質問内容ではないと思うので、何か読み違えてしまったのかもしれません。 >自分の責任で作るプログラムであれば、自分で考えて相応の理由があるのなら、どんな設計を採用しても構いません。 まったく仰る通りと思います。 >逆に言えばこの質問は設計作業の丸投げです。 何が逆なのかがわかりませんでした。また設計作業をお願いしている内容では全くないと思うので、何か読み違えてしまったのかもしれません。 >あなたが決めた設計で作っていく上で具体的な不具合が合った場合、その解決策について相談するのであればわかりますが。 その前段階の質問を許せないという方に無理してお願いするつもりはないので、そのようにつっかかられても困ってしまいます…
gentaro

2020/05/02 10:15

上のコメントでも指摘されているとおり、質問範囲が広すぎます。 これにすべて回答してくれというのは、あなたが自分で考えるのを放棄しているように見えます。 だから「設計の丸投げ」に見えるということです。 自分でケース提示をして、各ケースにおける疑問点を質問するのであればまだ理解できますが。 ここは学校じゃないので、あなたの教師を探す場所ではありません。 質問をもっと具体的かつ明確にしたらどうですか? あなたがどう捉えてるかは知りませんが、これはつっかかりではなく、回答を得るための提案です。
marorin

2020/05/02 10:19

なるほど、ありがとうございます。
marorin

2020/05/02 10:24

考えたのですがやはり今回は「こういうケースではこうした方がよかった」という皆様の事例を知りたいという趣旨のまま、質問をこのままにさせて頂くことご容赦くださいませ。
退会済みユーザー

退会済みユーザー

2020/05/03 03:24

こういう質問に回答しても、質問者の理解度が低い場合、長文で回答しても、「ありがとうございました」だけで、理解したのかどうかもわからない、回答しても手応えのないケースが多くて敬遠しちゃうんですよね… 例として二つのパターンを例示していますが、それぞれ、メリット・デメリットがあると思って質問されていると思いますが、ご自身ではどのようにお考えですか?
marorin

2020/05/03 05:41

>こういう質問に回答しても、質問者の理解度が低い場合、長文で回答しても、「ありがとうございました」だけで、理解したのかどうかもわからない、回答しても手応えのないケースが多くて敬遠しちゃうんですよね… なるほどたしかに。ご回答者様のお心の想像を欠いておりました。 >例として二つのパターンを例示していますが、それぞれ、メリット・デメリットがあると思って質問されていると思いますが、ご自身ではどのようにお考えですか? はい、私としては「複数アクションにまたいで日付順に取得したい」というケースではわける方がいいと考えています。例えば「followかfavociteした相手一覧リスト」を取得する際に、created_atカラムでのソートをかける必要がないためです。(1つにまとめればソートするまでもなく順番にデータが入っているので、このようなリストの取得が楽だろうという考えです) 逆にそういったケースでなければ3つに分けた方がすっきり見やすく保守性が高いのかな、程度の違いという認識しか持ち合わせておりません。 つまり3つにわけるメリットにピンと来ていないというのが正直なところですので、そのあたりについてご回答いただけましたら特にありがたく存じます。
gentaro

2020/05/03 05:58

だからその「あなたの考えたケース」をちゃんと質問文で提示して、その場合に懸念される事項について質問すれば良いのではないか?と提案したわけですが。少なくとも上記コメントで「3つにしないメリット」を感じており、「3つにわけるメリット」がわからない、という提示はできてるわけですよね?なら「3つにわけた場合のメリットを教えて下さい」という質問で済むじゃないですか。 そうじゃなくて「それぞれのケースのメリット・デメリットを全て提示せよ」みたいなのは、試験問題でも出してるつもりか?と思うわけですよ。ここまでのやりとりでそれが理解できていないようなら、どうぞご自身で教材を探して勉強してください、としかならん気がしますけど。 https://teratail.com/help/avoid-asking 「teratailは困っている人の質問を解決するサービスです。そのため、漠然とした興味から票を募るような質問や、意見の主張をすることを目的とした投稿は推奨していません。 何か困っている理由があり、最適解を見つける為の知見を得たい場合は、その理由や何が知りたいのかを明確に記述してください。」 具体的に何に困ってます? 「わけないメリット」を感じており、デメリットを感じていないなら、「困っていること」が無いですよね?
marorin

2020/05/03 06:40

どうでしょうか…このあたりでご容赦ください。
gentaro

2020/05/03 06:49

別に怒ってるわけじゃないし、私が絶対的に正しいわけでもないんで、私の意見に納得がいかないようならそのままの質問で良いと思いますよ。 それで回答がつくこともあるでしょうから、気長に待ってみれば良いと思います。 ガイドラインを読んでれば当然理解されていると思いますが、質問は具体的である事がここでは求められているため「○○についてケース分けして全部説明して」というのは傾向として回答が付きにくいだけなので。(本来それは自分で学ぶべきことで、学んでて理解が出来ない箇所を質問することがガイドライン的に求められてるから)
退会済みユーザー

退会済みユーザー

2020/05/03 06:54 編集

@gentaro さん まあまあ… @marorin さん この欄は、あくまで「質問への追記・修正の依頼」をする欄なので、gentaroさんのいうように、質問文を編集して追記して欲しいです。
gentaro

2020/05/03 07:05

@Kosuke_Shibuya さん 宥められても困りますがw 「範囲の広すぎる質問」は「技術解説のブログ記事を一本書け」と要求しているのと実態があんまり変わらないので、ボランティア回答者に求めてもなかなか回答付かない(絶対ないとは言わないけど)と言えば伝わるかな。
marorin

2020/05/03 07:09 編集

@Kosuke_Shibuya さん わかりにくい質問に対して本当にありがとうございます。やりとりの内容を追記させて頂きました。 @gentaro さん 伝わりました。どうもありがとうございます。
javahack

2020/05/03 08:44

解決済みですが、気になった点が。 > (1つにまとめればソートするまでもなく順番にデータが入っているので、このようなリストの取得が楽だろうという考えです) 上記の意味が1テーブルならORDER BY不要という考えであれば間違っています。 データ取得時はORDER BYなしでは取得順は保証されないと考えて必ずORDER BYを付けるようにした方が良いです。
marorin

2020/05/03 08:49

これはものすごく助かる情報をありがとうございます。それを知らなければ順番がおかしくなる原因が特定できなくなるところでした。わざわざ解決済みの質問を見て頂き、それをこう的確に解釈してコメントくださるとは…深く感謝致します。
guest

回答1

0

ベストアンサー

設計に正解はない

この先プログラミングを続けてゆくのであれば、経験することはあると思いますが、設計が正しかったかどうかは後になってみないとわかりません。
その多くの場合は、運用後にわかります。

その多くの場合とは、「機能追加」の時にわかるのがほとんどです。

例示のケースの場合

Twitter のようなものを作ってみたいというケースでは、ある意味ゴール(最終形)が決まっているものなので、ある種正解が導きやすいかとは思います。
ただ、このプロダクトの所有者が、あなた自身であって運用もあなたが行うものであれば、自由に作っていいと思うし、データベースの設計もあなたが思うようにやればいい。
仮に、このプロダクトが他の誰かの発注によって作っているものであれば、話は変わります。

プロダクトが完成し、順調に運用をして2年が経過した頃、こんな頃を言ってきました。

「ブロックとは違って、ミュート機能を追加して欲しい」

どうしますか?

action_namemute を追加して…mute用のフォームやボタンを作成して…
となりますよね?

無事運用になりました。

それから、1年後…発注者から…

そして、actionの数は30を超えました…

こうなったら、今の設計、間違いとは言えないけど、煩雑になりますね。
もし不具合があって、調査するにも大変です。

設計の可否は単純にソースコードだけでは語れないのです。
お客さんは誰?どんな人?運用して管理するのは誰?その人のスキルレベルは?

それを含めて設計なんです。

設計の良し悪しは「ケースバイケース」です。

もし自分が、後者の方法をとったとしても、actioon_name で種類を区別っするような設計はしないでしょう。
action テーブルには、 action_type_id を設定し、action_type テーブルでアクションをマスター化しますね。
「フォローしている人」を抽出したい時、以下のSQLを投げることになりますよね?

SELECT * FROM action WHERE action_name = 'follow';

文字列の検索は整数での検索より遅いわけだから、

SELECT * FROM action WHERE action_type_id = 1;

のほうが高速だし、index の性能も高いわけです。

強いて言えば、正規化はしておけ

ちなみに、私が作るなら、前者の方法とります。
何故ならば、後者の場合、外部キー制約使えないから。

投稿2020/05/03 07:15

編集2020/05/03 07:29
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

marorin

2020/05/03 07:53

>それを含めて設計なんです。 大変多くのご経験のある方だとお見受けしました。このようなご視点を授けてくださり感謝申し上げます。 >もし自分が、後者の方法をとったとしても、actioon_name で種類を区別っするような設計はしないでしょう。 >のほうが高速だし、index の性能も高いわけです。 なるほど。ありがとうございます。 >何故ならば、後者の場合、外部キー制約使えないから。 他の点は知識として頂戴致しましたが、この点は本質問の決定打となりました。 外部キー制約を知らなかったので調べてみましたところ、存在検証できるというのは大変便利な機能で今回の件にぴったりですね。 現状も存在検証はしているのですが、INSERTする前に毎回 favoriteなら → SELECT tweet_id FROM tweets WHERE tweet_id=1 follow,blockなら → SELECT user_id FROM users WHERE user_id=1 などで当該データについて存在検証するという方法をとっておりました。 外部キー制約を使えばこれらSELECTが不要となるのは魅力的です。 どうもありがとうございます。私も後者にしたいと思います。
marorin

2020/05/03 07:55

すみません外部制約キーについてですが、 後者のtarget_idでは、そのtarget_idがあるのがusersテーブルなのかtweetsテーブルなのか判別できない。(faroriteならweetsテーブルにあるし、follow,blockならusersテーブルにある。) よって後者では外部キー制約が使えない。 このような理解であっていますでしょうか?
退会済みユーザー

退会済みユーザー

2020/05/03 07:58 編集

そういうことです。
marorin

2020/05/03 08:13

どうもありがとうございます。いくつか例が知りたいと思っておりましたが決め手となりましたので早速ベストアンサーとさせて頂きました。
退会済みユーザー

退会済みユーザー

2020/05/03 09:29

例示しても応用はできないものです。 自分もそう言うケースをリストアップしているわけではないですし、その都度、用件に合わせて設計するものと思っています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問