【问题标题】:Many to many vs one row [duplicate]多对多与一行[重复]
【发布时间】:2015-02-03 15:41:36
【问题描述】:

我很感兴趣,多对多关系如何以及为什么比将信息存储在一行中更好。

示例:我有两个表,用户和电影(非常大的数据)。我需要建立关系“视图”。 我有两个想法:

  1. 在“用户”表中创建另一个名为“views”的列,我将在其中以字符串的形式存储此用户观看过的电影的 ID。例如:“2,5,7...”。然后我会在 PHP 中处理这些信息。
  2. 创建新表 users_movies(多对多),其中包含 user_id 和 movie_id 列。 user_id=5 和 movie_id=7 的行表示用户 5 观看了电影 7。

我很想知道哪种方法更好,为什么。请考虑到数据相当大。

【问题讨论】:

  • 想象一下:如果您想创建一个看过特定电影的用户列表,或者只是计算有多少用户看过该电影,该怎么办?您必须获取所有数据,然后遍历它以过滤看过该电影的用户。特别是由于您将拥有大量数据,因此效率不会很高。这就是发明关系数据库的原因。
  • 方法一就像试图“unsqlize”一个 sql 数据库

标签: php mysql


【解决方案1】:

第二种方法几乎在所有方面都更好。您不仅可以利用 DBs 索引更快地查找记录,还可以使修改变得容易得多。

【讨论】:

    【解决方案2】:

    方法 1) 只需使用类似“...field_in_set(movie_id, user_movielist) ...”的 SQL 即可回答“用户 X 看过哪些电影”的问题。但反过来(“哪个用户确实看过电影 x”)在 sql 基础上不起作用。

    这就是为什么我总是选择方法 2):清晰的规范化结构,两种方法都是简单的连接。

    【讨论】:

      【解决方案3】:

      这只是关于您的需求。如果您需要性能,那么您必须接受信息的冗余并添加一列。如果您的主要目标是尊重规范化范式,那么您根本不应该有冗余。 当我必须做这种类型的选择时,我会尝试估计冗余的空间损失与感兴趣的查询的频率及其性能。

      【讨论】:

        【解决方案4】:

        还有一些想法。

        在第一种情况下,如果您查找特定用户,您可以轻松获得他们看过的电影的 ID 列表。但随后需要单独的查询来获取详细信息,例如这些电影的标题。这可能是一个使用 IN 和 ID 列表的查询,或者每个电影 ID 一个查询。这将是低效且笨重的。

        对于 MySQL,在这种情况下可能会使用 FIND_IN_SET() 函数加入(尽管这样做的不利方面是您误入非标准 SQL)。您可以使用 ON FIND_IN_SET(film.id, users.film_id) > 0 将您的电影表加入用户。但是,这不会使用索引进行连接,而是涉及一个函数(虽然它的作用很快,但在数千行上执行时会很慢)。

        如果您想找到观看过特定用户观看过的任何电影的所有用户,那么这有点困难。您不能只使用 FIND_IN_SET,因为它需要一个字符串和一个逗号分隔的列表。作为单个查询,您需要将特定用户连接到电影表以获取大量中间行,然后再次将其与用户连接(使用 FIND_IN_SET)以查找其他用户。

        SQL 中有一些方法可以拆分逗号分隔的值列表,但它们很混乱,任何必须维护此类代码的人都会讨厌它!

        这些都是软糖。使用第二种解决方案,这些很容易做到,并且任何生成的连接都可以轻松使用索引(并且可能整个查询可以只使用索引而不接触实际数据)。

        第一个解决方案的另一个问题是数据完整性。您将必须手动检查电影是否不会为用户出现两次(使用第二种解决方案,这可以使用唯一键轻松执行)。您也不能只添加一个外键来确保用户的任何电影 ID 确实存在。此外,您必须手动确保在分隔的 id 列表中没有输入任何字符串。

        【讨论】:

          猜你喜欢
          • 2022-01-19
          • 2017-05-17
          • 2020-04-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多