两者都不是一个很好的选择。
选项 1 是一个糟糕的主意,因为它使通过电子邮件查找用户成为一项复杂且低效的任务。您实际上需要在用户记录中的电子邮件字段上执行全文搜索才能找到一封电子邮件。
IMO,选项 2 确实是一个更糟糕的想法,因为它使任何周围的代码编写起来都非常痛苦。再次假设您需要查找具有值 X 的所有用户。您现在需要枚举 30 列并检查每一列以查看该值是否存在。痛苦!
以这种方式存储数据——一个或多个数据元素——在数据库设计中非常常见,正如 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
语句是可选的——没有它,设计也可以工作,但是,该行会导致数据库强制建立关系。例如,如果您尝试插入一条user_email
auser_id
为 10 的记录,则必须有一条user
a 为 10 的对应记录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 地址返回一行。如果您有 5 个用户并且每个用户有 5 个电子邮件地址,则上述查询将返回 25 行。
根据您的应用程序,您可能希望每个用户获得一行,但仍然可以访问所有电子邮件。在这种情况下,您可以尝试一个聚合函数,例如GROUP_CONCAT
它将为每个用户返回一行,并带有一个逗号分隔的属于该用户的电子邮件列表:
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;
同样,根据您的应用程序,您可能希望向电子邮件列添加索引。
最后,在某些情况下,您不需要规范化的数据库设计,而带有分隔文本的单列设计可能更合适,尽管这些情况很少见。对于大多数普通应用程序,这种类型的规范化设计是可行的方法,并将帮助它更好地执行和扩展。