我想知道存储的最佳方法是什么,例如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 有两件事很重要。第一个,正如@BryceAtNetwork23 所指出的,没有必要在 User_Language 表上放置一个 id。第二个是,你应该了解joins,特别是MySQL Joins(因为 SQL 在不同的数据库引擎中往往会有所不同)。在你深入挖掘之后,你将能够看到在前面的查询中加入 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,您可以获得语言。缺点是搜索它会很痛苦。您如何让所有用户使用“西班牙语”语言?(这里的底线是你不能索引你的数据)。另一个缺点,现在有点过时了,是磁盘空间的过度使用。在数据库和规范化被发明的时候,磁盘空间非常昂贵。所以,存储这个:
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 表并获取语言列,将其拆分为 ";" 并寻找 id 1。
这就是为什么我们开始使用我之前向您展示的方法。
所以,到目前为止一切顺利。很好的解释;)
大免责声明
正如我之前所说,有几种方法可以做到这一点。这取决于您的情况以及您想要达到的目标。如果您想根据该列进行搜索(例如,给我说英语的用户),您应该考虑我在答案顶部告诉您的设计。
现在有一种数据解决方案的“新浪潮”,称为 no-sql 数据库(它会有所不同),它们试图对数据进行非规范化。如果您担心模式的过度规范化,您应该看一下。我推荐你使用 MongoDB 和 CouchDB,因为它们更容易上手。
关于联接
不用担心 2 个连接的性能。如果你有性能问题,那不是为了这个。数据库引擎就是为此目的而创建的。有了良好的内存缓存和索引优化,它应该可以顺利运行。
是的,最好的方法是使用带有列lang_id
和的附加表user_id
。在那里您可以存储任意数量的用户/语言关联(每行一个)。
创建表 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 存储了哪些用户知道哪些语言的关联。
我认为你应该考虑有两张桌子。一个与users
一个与languages
。它更容易维护,也更容易对joins
这些表进行操作。