どちらもあまり良い選択肢ではありません。
オプション 1 は、電子メールでユーザーを検索するのが複雑で非効率的な作業になるため、お勧めできません。1 つの電子メールを見つけるには、ユーザー レコードの電子メール フィールドで全文検索を実行する必要があります。
オプション2は、周囲のコードを書くのが非常に面倒になるため、実際には最悪のアイデアです。もう一度、値 X を持つすべてのユーザーを検索する必要があるとします。ここで、30 列を列挙し、それぞれをチェックして、その値が存在するかどうかを確認する必要があります。痛い!
このようにデータを保存する方法 (データの一部の要素の 1 つ以上) は、データベース設計では非常に一般的であり、Adam が以前に述べたように、ほとんどの場合、正規化されたデータ構造を使用して解決するのが最善です。
これはそのようにタグ付けされているため、MySQL で記述された正しいテーブル構造は次のようになります。
ユーザー テーブル:
CREATE TABLE user (
user_id int auto_increment,
...
PRIMARY KEY (user_id)
);
メールテーブル:
CREATE TABLE user_email (
user_id int,
email char(60) not null default '',
FOREIGN KEY (user_id) REFERENCES user (user_id) ON DELETE CASCADE
);
ステートメントはオプションです。FOREIGN KEY
設計はそれがなくても機能しますが、その行により、データベースは関係を強制します。たとえば、a が 10 のレコードを に挿入しようとするuser_email
と、aが 10 の対応するレコードuser_id
がなければ、クエリは失敗します。は、テーブルからレコードを削除すると、それに関連付けられているすべてのレコードも削除されることをデータベースに伝えます(この動作が必要な場合とそうでない場合があります)。user
user_id
ON DELETE CASCADE
user
user_email
もちろん、この設計は、ユーザー レコードを取得するときに結合を実行する必要があることも意味します。次のようなクエリ:
SELECT user.user_id, user_email.email FROM user LEFT JOIN user_email ON user.user_id = user_email.user_id WHERE <your where clause>;
システムに保存されている user_email アドレスごとに 1 行を返します。5 人のユーザーがいて、各ユーザーが 5 つの電子メール アドレスを持っている場合、上記のクエリは 25 行を返します。
アプリケーションによっては、ユーザーごとに 1 つの行を取得したい場合がありますが、それでもすべてのメールにアクセスできます。その場合、GROUP_CONCAT
ユーザーごとに 1 つの行を返し、そのユーザーに属する電子メールのカンマ区切りのリストを返すような集計関数を試すことができます。
SELECT user.user_id, GROUP_CONCAT(user_email.email) AS user_emails FROM user LEFT JOIN user_email ON user.user_id = user_email.user_id WHERE <your where clause> GROUP BY user.user_id;
繰り返しますが、アプリケーションによっては、電子メール列にインデックスを追加したい場合があります。
最後に、正規化されたデータベース設計が望ましくない状況がいくつかあります。そのような状況はほとんどありませんが、区切りテキストを使用した単一列の設計がより適切な場合があります。ほとんどの通常のアプリケーションでは、このタイプの正規化された設計が最適であり、パフォーマンスと拡張性を向上させるのに役立ちます。