【问题标题】:Best way to store variable number of preferences?存储可变数量偏好的最佳方式?
【发布时间】:2017-07-04 04:51:00
【问题描述】:

我需要存储可变数量的用户偏好。例如,如果我们谈论电影,用户 1 喜欢电影 [A, B, C],用户 2 喜欢 [C, D] 等。 将这些“正确”存储在表中的最佳方法是什么 - 这样我就可以有效地搜索这些首选项,如果有新类型的首选项等,就没有大量表。

【问题讨论】:

  • 您的两个要求是相互对立的。 Properly 表示归一化,即a multitude of tables if there are new types of preferences。选择你想做得对还是轻松。

标签: sql database database-design


【解决方案1】:

有一个包含 users 的表,一个包含 movies 的表和第三个表(preferences),您可以在其中将用户映射到电影。像这样一个用户可以喜欢多部电影,而不同的用户可以喜欢同一部电影。它基本上是一个 M:N 关系。这是你要找的吗?

【讨论】:

  • 但是这不符合如果有新的偏好没有大量表的要求
  • 无论 OP 是否需要创建新表,这都是正确的答案。
【解决方案2】:

我建议您查看Entity-Attribute-Value model
这为更改逻辑模式和基数提供了极大的灵活性。
stackoverflow postings 讨论了各种 EAV 实现和细节,也许您可​​以从 this one 开始,因为它通常涵盖了这里提出的问题类型。

例如,当应用程序发展并需要其他类型的首选项时,根本不需要修改物理模式(支持 SQL 表),新的首选项将成为属性表中的一个条目。

EAV 模型的主要缺点是表结构稍微复杂一些,而且效率下降(比如有数百万个实体)。
使用普通的关系模型,数据模型在数据库 [物理] 模式中更加明显。 Le 效率损失主要来自于 Values 表一次只存储一个属性值(防止创建组合索引等)并且相对于存储相同的记录所需的记录数可能会变得相当大纯关系形式的数据。

编辑(关于性能)
我已经相对成功地处理了多达 400 万行的数据实例,每个/大多数平均具有十几个属性。我们可以从中得到的精确“里程”随着数据的稀疏性和某些属性值的相对选择性而变化。有几个“交易技巧”可以提高性能,但代价是使实施更加复杂:

  • 将最常共享的单值属性存储在 Entity 表中,而不是(或除了)Values 表中。
  • 使用多个值表。这样的“分区”可以由数据类型、属性 ID 范围驱动......

【讨论】:

  • 同意这对小商店有好处,但随着规模的扩大,变成一场噩梦
  • EAV 将每个临时用户变成您的数据库设计师。在做这件事之前你需要好好想想。
【解决方案3】:
-- Predicate: User has id number :user_id.
create table users (
  user_id integer primary key
);

-- Predicate: Movie has id number :movie_id and name :movie_name.
create table movies (
  movie_id integer primary key,
  movie_name varchar(150) not null  -- Movie names aren't unique.
);

-- Predicate: User :user_id likes to watch movie :movie_id.
create table movie_preferences (
  user_id integer references users (user_id),
  movie_id integer references movies (movie_id),
  primary key (user_id, movie_id)
);

如果您以后有不同类型的偏好,例如餐厅,那么您需要一张餐厅表和一张餐厅偏好表。

-- Predicate: Restaurant has id number :restaurant_id and name :restaurant_name,
-- and is known for its :known_cuisine cooking.
create table restaurants (
  restaurant_id integer primary key,
  restaurant_name varchar(150) not null,
  known_cuisine varchar(30) not null
);

-- Predicate: User :user_id likes to eat at restaurant :restaurant_id.
create table restaurant_preferences (
  user_id integer references users (user_id),
  restaurant_id integer references restaurants (restaurant_id),
  primary key (user_id, restaurant_id)
);

您需要额外的表格来获得额外的偏好,因为电影与餐馆不同,“我喜欢‘壮志凌云’”与“我喜欢汉堡王”的意思不同。

您不会有很多桌子。每个偏好只有一张桌子。 (因为您必须先实现一张餐厅表才能识别它们,对吧?)

【讨论】:

    【解决方案4】:

    【讨论】:

    • 您是否建议为他的列表使用逗号分隔的字符串?还是您建议每个用户对每部电影都有一个字段?无论哪种方式,这都是一个糟糕的解决方案。
    • 这取决于偏好的数量。如果有无限的偏好,是的,它很糟糕。否则它比 EAV 更有效
    【解决方案5】:

    您能否创建一个包含可变数量偏好的排序查找表?

    在创建新首选项时,会将它们放入具有相应 ID 的表中。

    然后用

    创建一个连接表(多对多)
    UserID
    PreferenceID
    

    【讨论】:

      猜你喜欢
      • 2020-08-12
      • 2010-10-01
      • 1970-01-01
      • 2011-11-26
      • 1970-01-01
      • 1970-01-01
      • 2014-09-03
      • 1970-01-01
      • 2023-04-08
      相关资源
      最近更新 更多