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

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

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

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

PHP

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

Q&A

解決済

4回答

1654閲覧

いいね!や評価するボタンのRDBの構造

pegy

総合スコア243

MySQL

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

PHP

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

0グッド

2クリップ

投稿2019/07/22 08:06

現在、投稿型サイトを制作しており、一点構造上どのようにすべきか悩んでいる点がございます。

例えば、本サービスのteratailも採用していると思うのですが、userログインされていることを前提に
投稿された記事に対して「評価する」ボタンが準備されており、①userと②評価されている記事の情報が紐付いていると思います。より具体的に申し上げれば、例えばAと言う、第3者の質問記事について、評価ボタンを押した場合、評価が1つ追加され、ページリロード後に同じ記事を閲覧すると当然評価が1つ追加されており、改めてクリックすると1件減少し、取り下げることができるようになっていることから、「紐付いている」と表現いたしました。

さて、ここでMYSQL上現在、以下のような2つTABLEあります。
1.post_table(個別記事の情報に関するtable)

SQL

1postid int(10) PRIMARY KEY AUTO INCREMENT/*一意の記事ID*/ 2postby varchar(20) /*投稿者の名前*/ 3postcontent varchar(255) /*投稿内容*/

2.user_table(ユーザ情報の関するtable)

SQL

1userid int(10) PRIMARY KEY AUTO INCREMENT/*一意のuserID*/ 2username varchar(10)/*投稿者の名前*/

実務上、どのようにするのか是非アドバイスをお尋ねしたいのです(必ずしも答えは一つではないので、こうするのが良いですよというご意見でも結構ですので)

このような場合、

  1. post_tableのように記事情報に一つカラムを設けて、"1,4,7"(番号はuserid)のようにカンマ区切り等で複数つなげた情報を持たせるべきでしょうか?または、同じような話ではありますが、user_table側に一つカラムを設けて、"1,4,7"(番号はpostid)として、ユーザー側情報に「いいね」をした記事の情報を持たせるべきでしょうか?

2) または、post_tableやuser_tableにいいねがあるたびにカラムを増やしていく方法(思いつきで申し上げているの現実的かどうかは定かではないのですが)

  1. または、記事ごとに記事ごとにまた別のtableを設けて、ユーザーから「いいね」をされるたびにその該当tableを参照して、追加または削除の判断をする(複数のテーブルを管理したことがなく、実務的にこのように無限に増える可能性があるテーブルを作っていくことが実務的に正しいかどうかが自身、懐疑的ではあります)

上記で申し上げた、「ユーザー」と「いいね」の紐付け及びその一般的な管理のしやすさ(例えば、「いいね」が押された場合に、既にされているかどうかの検索のスピードや上記で述べた、無限にテーブルが増えていってしまう煩雑さを含めて)について、どのような方法が実務的なのでしょうか。

漠然とした抽象的な質問になってしまって申し訳ございません。もっと具体的にこのような機能を実装したいので、その場合はどのようなテーブルの持ち方をすれば良いですかとお問い合わせできれば良いのですが、なにぶん初心者で理解が不足している箇所も多々あると思いますが、取り掛かるにあたってのアドバイスを願えれば幸いです。

よろしくお願い申しあげます

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

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

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

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

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

guest

回答4

0

ベストアンサー

どのような方法が実務的なのでしょうか。

1~3、どれも通常使いません。

post_iduser_idの2列をもった中間テーブルを作って、いいねがつくたびにそのテーブルに行を追加する、という形が適切です。

投稿2019/07/22 08:08

maisumakun

総合スコア145183

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

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

maisumakun

2019/07/22 08:16

特に、「動的にテーブル定義を変える」あるいは「データに応じて動的にテーブルを作成する」というような構造は、よほど特殊な理由がない限り取ってはいけません。
pegy

2019/07/22 08:19

コメント誠にありがとうございます。とても嬉しいです! 仰る中間テーブルの構造のイメージなのですが、例えば以下のようなイメージで、それぞれのカラムを設定して、「いいね」を押されたらwhere句 + and で postid and useridをkeyにしてステータス(goodflag)を探して更新していく、そして、総数についても同じようなkeyで個数をカウントすると言ってものが近いでしょうか? postid int(10) userid int (10) goodflag int(10)
maisumakun

2019/07/22 08:21

goodflagなしで、「そのテーブルに行が存在する」=「いいねしている」と判定する形のほうがスッキリしているかなと思います(いいねを外した場合は行を削除する)。
pegy

2019/07/22 08:30

コメントバック誠にありがとうございます。 一瞬、「いいね」したことがあるかどうかという事実を残すことに意義もあるかと思ったのですが、(つまり以下の3パターン)そもそもいいねしたが取り消された事実があることにあまり意味はない(無駄に行も増えるだけ)と思ったので、一旦、ご助言に従おうと思います。無論、実際に意味があるかどうかは、どのような運用をしたいかに依存することかと思いますので、必要に応じて、設計を考えてみようと思います。 > 一度「いいね」したら行が存在して1 > 一度「いいね」して行が存在するが0 > そもそも「いいね」されたことがないので行が存在しない 本当にご助言に助けられました。初心者の発想や稚拙な質問にお答えいただいたことに侘びと御礼を申し上げます。
guest

0

その2つのテーブルに対する「いいね!」や「評価」の関係は、多対多の関係です。
正規化に照らすと多対多の関係は、中間テーブルやマップと言われるテーブルを追加するのが、一般的です。

以下が分かり易そうだったのでリンクしておきます。
多対多のリレーションシップ

POSTGRESなどの配列が扱えるDBMSであれば、中間テーブルを用いずに配列にする方が効率的な場合もありますが、MySQLだと中間テーブルを用いた方が吉だと思います。

投稿2019/07/22 08:36

sazi

総合スコア25173

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

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

m.ts10806

2019/07/22 08:38

個人的な興味で意見を聞きたいです。 MySQLでJSON型を利用する場合と中間テーブルを利用する場合とどちらが好ましいのでしょうか。
sazi

2019/07/22 08:48 編集

中間テーブルはあくまで多対多を解決するものですので、JSON型を引き合いにだすのはちょっと違和感があります。 json型を適用するのは、マルチカラムアトリビュートパターンの場合かなと思っていますので、この場合は中間テーブルの方が好ましいと考えます。
pegy

2019/07/22 08:45

コメントありがとうございます。 「多対多のリレーションシップ」と言う概念を初めて認知しました。 また、配列を扱える「POSTGRES」二存在も初めて知りました。特に前者について考えとして今後のために十分理解すべきと思いますので、少し時間をかけて読ませていただきます。 すぐには理解できない領域ゆえに、時間がかかるため、一旦ベストアンサーを選択して、回答自体はcloseいたします。 本サイトの運用として、コメントが継続しているにかかわらず、closeするのは不適切であればその旨ご指摘ください。解除をいたします。 よろしくお願い申しあげます。
m.ts10806

2019/07/22 08:48

saziさん ありがとうございます。 >中間テーブルはあくまで多対多を解決するものですので、JSON型を引き合いにだすのはちょっと違和感があります。 json型を適用するのは、マルチカラムアトリビュートパターンの場合かなと思っています。 あまり今回のケースで使うメリットはないということですね。
sazi

2019/07/22 08:53 編集

@mst10806 さん この場合結合する事は必須でしょうから、json型よりも通常のインデックスの方が良さげですし。
m.ts10806

2019/07/22 09:04

saziさん >この場合結合する事は必須でしょうから 確かにそうですね。分解して結合して、となるとかなり無駄になりそうです。 勉強になりました。
mikkame

2019/07/23 03:58

> あまり今回のケースで使うメリットはないということですね 横から失礼します。 メリットどころかデメリットしかございません。 例えば、postsにgoodersカラムがあったとして(JSONでいいね!した人を入れることができる) 記事から、いいね!した人を取り出すのは簡単だが 自分がいいね!した記事を探すには全ての記事を取得してから出ないと計算できない。(自分が1件しかいいね!してないとしても) これは)1 で言われている,区切りと大差がない設計になります。 JSON型は、JSONがエンコード、デコードができる、VaildなJSONしか入らないカラムというだけ。 (あとSELECT結果をいれられるとかだった気が) PHP側でDECODEして処理してたのがSQL上で処理できるようになったよぐらいのレベル。 もちろん、Indexは効かない。全部json_decodeしてからWhereとかorderByをかけるイメージ。 いままでPHPでjson_encodeしてからinsertみたいな運用していた人からはTEXT型とあまり差がない。 ※ generated columを使えばJSON型をindexに追加できるが、その場合でも特定の要素しかindexにできないので微妙
m.ts10806

2019/07/23 04:12

mikkameさん 細かい補足ありがとうございます。 確かにほぼセパレータ管理と変わらないという感覚はありますね。 昔はよくJOINせずにループ時に毎回SELECT投げて名称とってくるとか平気で組んでた時期もあったので その組み方ならJSONのほうが処理は楽かなくらいの感覚ではいました。 今ではさすがにそんな組み方はしていないのできちんと設計時に中間テーブルは用意しますし。 「となるとJSON型ってどういうときにメリットを発揮するのだろう」とちょっと不明になったのもあります。
mikkame

2019/07/23 04:23

今までtextにjsonで突っ込んでたデータをSQLで操作できるようになったのでDB内だけでJSONを含めた統計を取れるようになったぐらいで、私たちのようなPhperにはメリットが薄い所感です
sazi

2019/07/23 04:24

@mikkame さん @mts10806さん MySQL一択でないなら、postgresの配列型やjson型に関する事を見られてみると、今後の選択肢が増えるかもしれません。 indexも適用できますし、配列やjsonに畳むことで、容量や性能によるメリットを享受できる場合がありますので。
guest

0

提示されているどのやり方でも実現は可能と思いますが(2だけは絶対にやっちゃダメだと思う)、記事ID「いいね」した人のユーザーIDだけを保管するテーブルを作って記事毎に「いいね」の数がカウントできるようにしたほうが良いとは思います。

どのような方法が実務的なのでしょうか

これですがご自身でも仰っているように「必ずしも答えは一つではない」のと同じで
「実務ではこれが一般的だよ」という答えも存在しません。

プロジェクトの方針によりけりで、扱うデータと全体の流れやバランスによって決定されるものと思います。

ちょっと思うところを追記:
作り次第では連投や外部からランキングを操作できてしまうので、その対応は必要に思います(これも要件次第)
まあ中には流行ってるように見せるべく内部的なデータ操作を行うケースもあるのでこれに限ったことではないですが。

投稿2019/07/22 08:12

編集2019/07/23 00:05
m.ts10806

総合スコア80842

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

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

m.ts10806

2019/07/22 08:19

3)を勘違いして読んでたため修正しています。
pegy

2019/07/22 08:21

コメントありがとうございます。1日頭を抱えていてたので、質問をしてよかったです。 さて、記事IDと「いいね」した人のユーザーIDだけを保管するテーブルよいうのは、おそらくmaisumakun様のコメントする中間テーブルに近いイメージかと推察しましたが、相違ございますでしょうか? よろしくお願い申しあげます。
m.ts10806

2019/07/22 08:26

maisumakunさんの回答を見る前に投稿したため重複していますが、言わんとすることは同じですね。
m.ts10806

2019/07/22 08:27

別の方の質問にも設計関係で回答したときにもアドバイスしたことがあるのですが、 実際に作ってみて分かることもあると思うので(これじゃダメだとか非効率だとか) とりあえず思うように作ってみて調整するというのもありです。
pegy

2019/07/22 08:32

コメントバックをいただきありがとうございます。 おかげさまで、道筋が見えてきました。お恥ずかしながらお二人が仰る設計のアイデアに至りませんでしたが、非常に勉強になりました。 仰る通り、実際に構築をしてみて、自身がやりたい運用の方向も兼ねて調整していきたいと思います!
m.ts10806

2019/07/22 08:34

完璧な設計って最初からするのは土台無理な話なので、 考えたことをミニマム構成で試してみて検証する作業は必要ですし、 それでOKだったとしても実装とかテストの中で気づく不具合や不整合も現場ではあります。 なので、「まず思ったように作ってみる」ところから気づきを得ることもあると思います。
guest

0

余談

いいね!や評価するボタンのRDBの構造

そもそも RDB が良いのか?みたいな話もあります。興味があれば調べてみると良いですよ。いいね!や評価するボタンは極単純な関係性を大量に生成するため RDB から切り出す Web サービスもそれなりの数、見受けられます。

投稿2019/07/22 23:21

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

pegy

2019/07/22 23:45

コメントをいただきありがとうございます。 RDB以外に情報を蓄積し、出力する方法があるなんて想像だにしませんでした。。しかも実際に本番環境で運用されているとは、、まだ私には雲をつかむような話(初心者のため、継続的にデータを保持するのはRDBと言う手段以外にウェブアプリケーションには存在しないと思っていたので)ですが、少し調べてみます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問