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

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

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

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

phpMyAdmin

phpMyAdminはオープンソースで、PHPで書かれたウェブベースのMySQL管理ツールのことです。

SQL

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

Q&A

解決済

3回答

814閲覧

データベース設計におけるnullの扱い

ikatako

総合スコア270

MySQL

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

phpMyAdmin

phpMyAdminはオープンソースで、PHPで書かれたウェブベースのMySQL管理ツールのことです。

SQL

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

0グッド

0クリップ

投稿2020/02/12 21:47

###知りたいこと
掲示板のテーブル設計ですが、1と2はどちらがいいのでしょうか。

1.UNIONで生じるnullを許す
2.あらかじめカラムにnullを許す

###1.UNIONで生じるnullを許す
下記のように「threads」と「comments」というテーブルに分けるならば、それらのカラムにnullは生じません。

↓「threads」
イメージ説明

↓「comments」
イメージ説明

ここでユーザーが
・スレッド1をフォロー
・ユーザー80をフォロー
としていたとき、

彼のタイムラインに
・スレッド1へ投稿されたもの
・ユーザー80が投稿したもの
を流すことを考えます。

その情報を取得すると以下のように「threads」と「comments」をUNIONして、null0などで埋めないといけないカラムが出てきてしまいます。

↓「UNIONしたもの」
イメージ説明

「thread_genre」は「threads」にしかないカラムだし、逆に「parent_comment_id」や「parent_thread_id」は「comments」にしかないカラムだからです。

###2.あらかじめカラムにnullを許す
他方、「threads」と「comments」というテーブルに分けず、下記のように「posts」に統合しておきますと、あらかじめnullを許しますが、UNIONするコストがかかりません。
タイムラインに流す情報の取得はSELECTだけで済みます。

↓「posts」
イメージ説明

###改めて
ネットで検索する掲示板のテーブル設計といえば「threads」と「comments」をわけるものばかりです。

しかし、タイムラインのように「threads」と「comments」を統合して走査するケースがある場合に鑑みますと、2がいいのではと感じます。

タイムラインの情報としていずれにせよnullが介在せざるをえないのならば、2はUNIONのコストが不要なためです。

テーブル設計は初めての初学者で、他にいい方法なども存じません。
2にすべきか、1にすべきか、他にもっと適切な設計があれば知りたいです。

尚、実際には「thread_genre」以外にもスレッドだけのカラムはたくさん(50個)ありますし、逆にコメントにしかないカラムもこの例よりたくさんあります。(なのでWordPressのようにEVAを採用するとレコードが増えすぎて心配ですし、取得のSQLの煩雑さも懸念されますのでEVAは避けたいです。)

アドバイス宜しくお願い致します。

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

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

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

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

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

maisumakun

2020/02/12 22:10

> スレッドだけのカラムはたくさん(50個)ありますし 具体的に、どのようなカラムがあるのでしょうか。
m.ts10806

2020/02/12 23:56

テーブルを作ってからどうにかしようとしてるから進まないわけで。 あと、質問についたアドバイスを一切受け入れるつもりないなら質問しないでもらいたいな。 そのスタンス続けると誰もアドバイスしなくなりますよ。
ikatako

2020/02/13 00:29

maisumakunさん、thread_time1、thread_time2のようなスレッドに関する微細な情報です。
yambejp

2020/02/13 00:30

画像とあわせてSQLの例示があると解説のしようもあるのですが
guest

回答3

0

そもそも論として、UNIONにはインデックスがかかりませんので、ある程度以上のデータ量を引くような場面では、速度が出ないため実用的になりません。

ということで、Postsにまとめるというのが適切となります。スレッドだけ、レスだけの項目については、別テーブルに切り出しておけばいいでしょう。

投稿2020/02/12 22:14

maisumakun

総合スコア146018

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

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

ikatako

2020/02/13 00:38 編集

いつもありがとうございます。 「別テーブルに切り出す」と仰いますと?あまり専門的な表現ですと追いつけないのですが、例えば「threads_sub」と「comments_sub」というテーブルを作り、必要に応じてJOINする(というかスレッドもコメントもそのsub情報は必ず必要なので常にJOINする)というイメージでしょうか? だとすると、JOINが必要になることと引き換えに、nullもUNIONもなくなり、1と2のいいとこどりに思えますね。
ikatako

2020/02/13 00:39

一つ疑問がございます。 subを使うというアドバイスですが、そのJOINのコストを、2でnullを許すことによるデメリットよりも小さく見積もっていらっしゃるということになるかと思います。ではそのデメリットとはどのようなものでしょうか?
guest

0

ベストアンサー

ざっと見た感じ検索項目が違うなら別々に検索してあとで
合算すればいいような気がします。
煩雑になるほどむしろ項目名、値の組み合わせでデータを持つほうが
効率的かも

投稿2020/02/13 00:33

yambejp

総合スコア116724

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

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

ikatako

2020/02/13 00:48

今回もご回答ありがとうございます。 >別々に検索してあとで合算すればいい 1回のSQLでnullを含むも結果を取得せず、threadsとcommentsにそれぞれSQLを流しnullはなくして、その結果をPHPで合算しソートするということですか?1回の方が速度面でのメリットが大きいように思えるのですが、速度を犠牲にしてまでnullを避けるのはどうしてなのでしょうか? >煩雑になるほどむしろ項目名、値の組み合わせでデータを持つほうが 効率的かも すみません、こちらはよくわかりませんでした。項目名、値の組み合わせでデータを持つ、というのは、どのような意味になりますでしょうか?
yambejp

2020/02/13 10:52 編集

> 1回の方が速度面でのメリットが大きいように思えるのですが、速度を犠牲にしてまでnullを避けるのはどうしてなのでしょうか? 逆です。1回でやることにこだわるとスピードを犠牲にします。 別テーブルから別のSQLを実行するならそれぞれにSQLを 発行するほうが圧倒的に効率的です > 項目名、値の組み合わせでデータを持つ、というのは、どのような意味 それを聞くなら、ご自身のテーブル設計をきちんと表示すべきです create table+insert文で例示いただければ こうしたらもっと効率的という修正方針も示せるかもしれません。
ikatako

2020/02/13 21:13

なるほど、スピードの件まったく思いつきませんでした。ありがとうございます。 create table+insert文の例示ですが、他の質問との兼ね合いもあり、ひとまずあいまいな状態で画像だけで質問してしまっておりました。まだ具体的な細部が未定です。にも拘わらずできる限りのご回答を頂いたことに改めて感謝申し上げます。
guest

0

彼のタイムラインに
・スレッド1へ投稿されたもの
・ユーザー80が投稿したもの
を流すことを考えます。

その情報を取得すると以下のように「threads」と「comments」をUNIONして

threads → comments という関係だからunionじゃなくてjoinでしょう。

そもそも、同じタイミングで発生するもので無い限りNullは発生します。
正規化されている状態でも、outer join すればNUllは絶対発生するものですから、これらのNull考慮はテーブル設計の段階で決まっている事です。

投稿2020/02/13 00:58

sazi

総合スコア25327

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

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

ikatako

2020/02/13 01:26 編集

こんにちは。いつもお世話になっております。 joinというのは横に連結する処理ですよね?しかしそれではタイムラインとしての表示(日付順に縦に並んだ表示)ができないのではないかと感じます。 スレッドt1,t2,t3が縦に並び、そのスレッドへのコメントが横に連結されると下記のようなテーブルが取得されると思うのですが、 1行目:t1のカラム, t1-c1のカラム, t1-c2のカラム, t1-c3のカラム 2行目:t2のカラム, t1-c1のカラム, t1-c2のカラム 3行目:t3のカラム, t1-c1のカラム, t1-c2のカラム ここからどうやってタイムラインとしての表示をソートすればいいのか、お恥ずかしながらイメージが及びません。(尚取得されたテーブルはPHPでjson_encodeしてJSで受け取る予定です。) また上記はt1へのコメントを3件としていますが、もし1000件あったとき横に大変な長さでカラムが連結されてしまいますが、そこは不自然ではないのでしょうか。
maisumakun

2020/02/13 01:19

> 1行目:t1のカラム, c1のカラム, c2のカラム, c3のカラム JOINの考え方がおかしいです。 「t1-c1」「t1-c2」「t1-c3」のような感じの多数の行が取れます。
ikatako

2020/02/13 01:36

なるほど。t1へのコメントは横にずっと連結されるのかと思っていました。改めてJOINをいくつか試して勉強しておきます。
sazi

2020/02/13 03:03 編集

threadsに対して複数のcommentsがある場合、それをjoinすると縦方向(複数行)展開されます。 これを、threads1行に纏めてcommentsを横方向に展開するような事は、クロス集計と呼びます。 MySQLだと結構手間(GROUP_CONCAT()が利用できるとは思います)なので、取得した側で編集する事も視野に入れられた方が良いかと思います。
ikatako

2020/02/13 21:09

なるほど、勝手にクロス集計をイメージしておりました。ケースバイケースで手間を考慮し手段を選定できるように早くなりたいです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問