什么是实现具有多值属性的数据库的最佳方法?

时间:2017-02-14 08:27:16

标签: mysql sql database

我正在尝试实现一个具有多值属性的数据库,并创建一个基于过滤器的搜索。例如,我希望我的people_table包含id,姓名,地址,爱好,兴趣(爱好和兴趣是多值的)。用户将能够检查许多属性,而sql将仅返回拥有所有属性的人。

我完成了学习,并找到了实现这一目标的一些方法,但我无法确定哪一个是最好的。

  1. 第一个是有一个表,其中包含人员的基本信息(id,name,address),另外两个表用于多值属性,另外一个表只包含其他表的键(我知道如何创建这个表,我还不知道如何实现搜索)。
  2. 第二个是拥有一个包含基本信息的表,然后是每个属性一个。所以我将有20个或更多的桌子(足球,油漆,高尔夫,音乐,徒步旅行等),它们只包含人们的ids。然后,当用户通过使用JOIN功能检查业余爱好和活动时,我将获得所需的结果(我不确定复杂性,所以我不知道如果有多快,将会有多快用户做了很多检查。)
  3. 最后一个是我在互联网上找不到的实现(我知道有一个原因:))但在我看来,这是最容易实现的,也是最复杂的。只使用一个表,它将基本信息正常,并且所有属性都作为布尔变量。因此,如果我的桌子中有1000个人,那么将只有1000个循环,并且我想象使用AND条件将会足够快。
  4. 所以我的问题是:我可以使用第三种实现方式,还是有一个很大的缺点,我无法获得?还有你建议我使用前两种方法中的哪一种?

2 个答案:

答案 0 :(得分:4)

这是典型的 n到m关系。它像这样工作

persons table
------------
id
name
address

interests table
---------------
id
name

person_interests table
----------------------
person_id
interest_id

person_interests包含一个人每个兴趣的记录。为了获得一个人的利益:

select i.name
from interests i
join person_interests pi on pi.interest_id = i.id
join persons p on pi.person_id = p.id
where p.name = 'peter'

您还可以为hobbies创建表格。要获得兴趣爱好,请在单独的查询中执行相同的操作。要在一个查询中获得两者,您可以执行类似这样的操作

select p.id, p.name, 
       i.name as interest, 
       h.name as hobby
from persons p    
left join person_interests pi on pi.person_id = p.id
left join interests i on pi.interest_id = i.id
left join person_hobbies ph on ph.person_id = p.id
left join hobbies h on ph.hobby_id = h.id
where p.name = 'peter'

答案 1 :(得分:0)

处理此问题的基本方法是使用多对多连接表。每个用户都可以有很多爱好。每个爱好都可以有很多用户。您可以在任何地方找到相关信息,@juergend already covered that

更难的部分是跟踪有关各种爱好和兴趣的不同信息。就像他们的爱好是"棒球"你可能想跟踪他们的位置,但如果他们的爱好是"旅行"你可能想跟踪他们最喜欢的国家。使用典型的SQL关系执行此操作将导致表和列的快速增长。

混合方法是使用新的JSON data type来存储一些非结构化数据。要扩展@ juergend的示例,您可以向Person_Interests添加一个字段,该字段可以存储有关该人感兴趣的一些详细信息。

create table Person_Interests (
    InterestID integer references Interests(ID),
    PersonID integer references Persons(ID),
    Details JSON
);

现在你可以补充一点,45人有兴趣12(旅行),他们最喜欢的国家是吉布提,他们去过45个国家。

insert into person_interests
    (InterestID, PersonID, Details)
    (12, 45, '{"favorite_country": "Djibouti", "countries_visited": 45}');

您可以使用JSON搜索功能查找最喜欢的国家是吉布提的每个人。

select p.id, p.name
from person_interests pi
join persons p on p.id = pi.personid
where pi.details->"$.favorite_country" = "Djibouti"

这里的优势是灵活性:兴趣及其属性不受数据库架构的限制。

缺点是性能。 JSON数据类型不是最有效的,indexing a JSON column in MySQL is complicated。良好的索引对于良好的SQL性能至关重要。因此,当您找出常见模式时,您可能希望将常用属性转换为实际表中的实际列。

另一种选择是使用table inheritance。这是Postgres的一个功能,而不是MySQL,我建议考虑切换。 Postgres还有better and more mature JSON supportJSON columns are easier to index

使用表继承,而不是必须为每个不同的兴趣编写一个全新的表,您可以创建从更通用的表继承的特定表。

create table person_interests_travel (
    FavoriteCountry text,
    CountriesVisited text[]
) inherits(person_interests);

这仍然包含InterestID,PersonID和详细信息,但它添加了一些特定的列,用于跟踪他们最喜欢的国家/地区以及他们访问过的国家/地区。

请注意text[]Postgresql also supports arrays这样您就可以存储真实的列表而无需创建另一个连接表。您也可以在MySQL中使用JSON字段执行此操作,但是数组提供JSON不支持的类型约束。