languages
ユーザーが望むだけ多くの言語を持つことができるテーブルでuser
、このフィールドが集中的に検索されるため、シリアル化されたデータを使用しないことを願っています。
エントリ数を制限することを考えていました。たとえば、最大 4 言語で、ユーザー テーブルには lang1、lang2 ..
これを達成するためのより良い方法はありますか?
これはデータベースの正規化と呼ばれます。具体的には、 「多対多」の関連付けをマップする必要があります
3 つのテーブルが必要です。
User(id, name)
Language (id, language_name)
User_Language(id,id_user,id_language)
ユーザー ID 3 のすべての言語を取得するには:
SELECT l.language_name
FROM User u
JOIN user_language ul ON (u.id=ul.id_user)
JOIN Language l ON (l.id = ul.id_language)
WHERE u.id = 3
編集:
@silkAdmin に注意する重要な点が 2 つあります。最初のものは、@ BryceAtNetwork23 が指摘したように、ID を User_Language テーブルに置く必要はありません。2 つ目は、 joins、特にMySQL Joinsについて学ぶ必要があるということです(SQL は DB エンジンごとに異なる傾向があるため)。もう少し掘り下げると、前のクエリで User テーブルを結合する必要がないことがわかります。これは次のように簡略化できます。
SELECT l.language_name
FROM user_language ul
JOIN Language l ON (l.id = ul.id_language)
WHERE ul.user_id = 3
ただし、最初の回答に追加して、作業を簡単にしました。
言語テーブルを使用する理由
私の答えは、私のやり方を反映しているだけです。求められたことを達成する方法はたくさんあります。と言って、私は自分自身を説明します。
極端に考えてみましょう。最初の極端な例は、上で述べたように、ユーザー テーブルに言語を格納することです。たとえば、列を持ち、値をセミコロンで区切ることができます。このようなもの
User: (1, "John", "spanish;english;japanese")
その利点は、参加する必要がないことです。ユーザーのIDを指定すると、言語を取得できます。欠点は、それを検索するのが本当に苦痛になることです。言語が「スペイン語」のすべてのユーザーをどのように取得しますか? (ここでの結論は、データにインデックスを付けることはできないということです)。もう 1 つの欠点は、ディスク領域の過剰使用です。DB と正規化が発明された当時、ディスク容量は非常に高価でした。したがって、これを保存します:
User: (1, "John", "spanish;english;japanese")
User: (2, "Mary", "spanish;english")
それは許せないことだった。それで、何人かの男が来て言った:「ねえ、IDを使ってみましょう。
User: (1, "John", "1;2;3")
User: (2, "Mary", "1;2")
Language (1,"spanish")
Language (2,"english")
10,000 人のユーザーと数百の言語の場合、これはディスク使用量の大幅な改善です (おそらく、現在では、これは当てはまりません。後で説明します)。これでディスクの問題は解決しましたが、検索の問題はまだ残っています。繰り返しますが、言語が「スペイン語」のすべてのユーザーをどのように取得しますか? さて、この設計では、users テーブルを反復処理して language 列を取得し、それを ";" で分割する必要があります。id 1 を探します。
そのため、以前お見せしたアプローチを使い始めました。
だから、これまでのところとても良いです。かなり良い説明;)
大きな免責事項
前述したように、これにはいくつかの方法があります。それはあなたのケースとあなたが何を達成したいかによって異なります。その列の観点から検索したい場合(たとえば、英語を話すユーザーを教えてください)、回答の上部で説明したデザインを検討する必要があります。
現在、データを非正規化しようとする、no-sql データベース (さまざま) と呼ばれるデータ ソリューションの「新しい波」があります。スキーマの過度の正規化が心配な場合は、それを確認する必要があります。MongoDB と CouchDB をお勧めします。これらのほうが始めやすいからです。
結合について
2 つの結合のパフォーマンスについて心配する必要はありません。パフォーマンスに問題がある場合は、このためではありません。DB エンジンは、この目的で作成されます。適切なメモリ キャッシュとインデックスの最適化により、スムーズに動作するはずです。
はい、最良の方法は、追加のテーブルを使用して、列lang_id
とを使用することuser_id
です。そこには、任意の数のユーザー/言語の関連付け (行ごとに 1 つ) を格納できます。
テーブル user_languages を作成します
user_id int,
language_id int,
制約あり:
PRIMARY KEY (user_id, language_id),
FOREIGN KEY (language_id) REFERENCES language(id),
FOREIGN KEY (user_id) REFERENCES users(id)
このような制約により、ユーザーは必要な数の言語を割り当てることができます。
これを達成する最善の方法は、USER テーブル、USER_LANGUAGES テーブル、および LANGUAGES テーブルを用意することだと思います。このようにして、ユーザーは必要な数の言語を持つことができます。
USER
user_id int
user_name varchar
USER_LANGUAGES
user_id int
lang_id int
LANGUAGES
lang_id int
lang_name varchar
USER には、ユーザーベースのフィールドが格納されます。LANGUAGES は、特定の言語 (英語、ドイツ語など) ごとにデータを格納します。USER_LANGUAGES には、どのユーザーがどの言語を知っているかの関連付けが格納されます。
2 つのテーブルを持つことを検討する必要があると思います。1users
つと 1 つlanguages
。joins
これらのテーブルは、保守が容易であり、実行も容易です。