是否应该将一长串 ID 存储在数据库的列中 table?
Should a long ordered list of ids be stored in a column of a database table?
假设我有 table 个用户,他们有一个 ID 列和一个排名列。
每个用户都可以按某种顺序对其他用户进行排名。
假设这个列表可以很长(某个常量的最大值,比如 10,000),但通常会短得多。
只需要存储和检索用户的整个列表,也就是说,每个列表都不需要是例如在查询中搜索。
一个想法是将其存储为逗号分隔字符串形式的 ID 列表。
唯一的缺点是外键无法将列表中的每个 id 连接到相应用户的 id 列,这意味着如果用户的 id 发生变化,它不会在列表中自动更改。然而,用户的id永远不会改变,所以这是一个原则问题(不破坏1NF?)。
另一个想法是创建一个 table,其中每个条目都有一个来自和至用户 ID 列以及一个排名列。这样做的缺点是 table 可能包含与用户数量相比非常多的记录(例如数十亿)。此外,在检索用户列表时,需要搜索许多记录。有重复的数据,例如排名现在是显式存储的,而不是隐式存储的,这意味着在列表中进行一次更改可能意味着属于该列表的所有记录都必须更新其排名列。
什么是更好的解决方案?是否有完全不同的解决方案?
编辑:
我想大多数人会说第二个是最好的,因为它是一个 关系 数据库,但是,你能说消极方面可以减轻或者为什么它们无关紧要吗?如果有序列表可能更长,例如每个都有数百万个元素,因此列表更像是一团数据,而等效的 table 可能包含数万亿个条目?
当使用 table 时,用户可能需要将排名复制到前端语言的数组中才能对其进行编辑,因此每次更改都必须在前端进行 -端和后端,或者必须删除旧记录并为新列表的每个元素插入一条新记录。
对于关系数据库来说,这通常不是一个好的设计。
存储以逗号分隔的值列表是一种非规范化。良好的关系数据库设计鼓励规范化。
所有类型的优化都以牺牲其他查询为代价改进一种类型的查询。在你的情况下,如果你只存储或检索整个 id 列表,那么它可能是一个很好的优化。但是,如果您想向列表中添加一个 id,或者搜索一个特定的 id,或者确保它们被正确排序,或者许多其他类型的操作,那么这些任务都没有得到优化。
使用逗号分隔的列表实际上有很多缺点,不仅仅是你提到的关于外键的缺点。我在这里写了一个关于这个的旧答案:Is storing a delimited list in a database column really that bad?
使用规范化设计使数据库更加灵活。也就是说,您可以 运行 对数据进行多种类型的查询,none 尤其不利。
因此,像非规范化这样的优化要求您确保预先知道哪些查询对您的项目很重要,并且您知道您不需要任何类型的查询,因为非规范化会使成本更高设计。或者,如果您偶尔确实需要这些查询,则不需要它们来提高效率。
您表示担心如果以规范化方式存储它会产生很多行,但大多数 RDBMS 产品可以处理数十亿行。
如果您创建了正确的索引,搜索应该不会扫描很多行。哪些索引是正确的取决于您需要优化哪些查询。
What if the ordered lists could be even longer, e.g. millions of elements each, so the lists would be more like a blob of data and an equivalent table could contain trillions of entries?
恕我直言,如果您必须解决那种规模的数据管理问题,那么您就不会在 Stack Overflow 上询问如何解决它。你会聘请一些资深的软件架构专家来解决它。
他们会告诉您基本相同的事情:您必须非常具体说明您需要针对这些数据执行哪些类型的查询,然后他们才能选择最佳架构支持那些特定的查询。因为在这种规模下,除了最佳方法之外,您无能为力。
如果您不需要解决“万亿元素”规模的问题,那么使用关系解决方案就足够了,并且提供了灵活性,如上所述。
我看到很多关于 Facebook 如何按其规模管理数据的问题。答案几乎总是:“他们做什么并不重要,因为你永远不必按照他们的规模去做他们所做的事情。”
假设我有 table 个用户,他们有一个 ID 列和一个排名列。 每个用户都可以按某种顺序对其他用户进行排名。 假设这个列表可以很长(某个常量的最大值,比如 10,000),但通常会短得多。 只需要存储和检索用户的整个列表,也就是说,每个列表都不需要是例如在查询中搜索。
一个想法是将其存储为逗号分隔字符串形式的 ID 列表。 唯一的缺点是外键无法将列表中的每个 id 连接到相应用户的 id 列,这意味着如果用户的 id 发生变化,它不会在列表中自动更改。然而,用户的id永远不会改变,所以这是一个原则问题(不破坏1NF?)。
另一个想法是创建一个 table,其中每个条目都有一个来自和至用户 ID 列以及一个排名列。这样做的缺点是 table 可能包含与用户数量相比非常多的记录(例如数十亿)。此外,在检索用户列表时,需要搜索许多记录。有重复的数据,例如排名现在是显式存储的,而不是隐式存储的,这意味着在列表中进行一次更改可能意味着属于该列表的所有记录都必须更新其排名列。
什么是更好的解决方案?是否有完全不同的解决方案?
编辑: 我想大多数人会说第二个是最好的,因为它是一个 关系 数据库,但是,你能说消极方面可以减轻或者为什么它们无关紧要吗?如果有序列表可能更长,例如每个都有数百万个元素,因此列表更像是一团数据,而等效的 table 可能包含数万亿个条目?
当使用 table 时,用户可能需要将排名复制到前端语言的数组中才能对其进行编辑,因此每次更改都必须在前端进行 -端和后端,或者必须删除旧记录并为新列表的每个元素插入一条新记录。
对于关系数据库来说,这通常不是一个好的设计。
存储以逗号分隔的值列表是一种非规范化。良好的关系数据库设计鼓励规范化。
所有类型的优化都以牺牲其他查询为代价改进一种类型的查询。在你的情况下,如果你只存储或检索整个 id 列表,那么它可能是一个很好的优化。但是,如果您想向列表中添加一个 id,或者搜索一个特定的 id,或者确保它们被正确排序,或者许多其他类型的操作,那么这些任务都没有得到优化。
使用逗号分隔的列表实际上有很多缺点,不仅仅是你提到的关于外键的缺点。我在这里写了一个关于这个的旧答案:Is storing a delimited list in a database column really that bad?
使用规范化设计使数据库更加灵活。也就是说,您可以 运行 对数据进行多种类型的查询,none 尤其不利。
因此,像非规范化这样的优化要求您确保预先知道哪些查询对您的项目很重要,并且您知道您不需要任何类型的查询,因为非规范化会使成本更高设计。或者,如果您偶尔确实需要这些查询,则不需要它们来提高效率。
您表示担心如果以规范化方式存储它会产生很多行,但大多数 RDBMS 产品可以处理数十亿行。
如果您创建了正确的索引,搜索应该不会扫描很多行。哪些索引是正确的取决于您需要优化哪些查询。
What if the ordered lists could be even longer, e.g. millions of elements each, so the lists would be more like a blob of data and an equivalent table could contain trillions of entries?
恕我直言,如果您必须解决那种规模的数据管理问题,那么您就不会在 Stack Overflow 上询问如何解决它。你会聘请一些资深的软件架构专家来解决它。
他们会告诉您基本相同的事情:您必须非常具体说明您需要针对这些数据执行哪些类型的查询,然后他们才能选择最佳架构支持那些特定的查询。因为在这种规模下,除了最佳方法之外,您无能为力。
如果您不需要解决“万亿元素”规模的问题,那么使用关系解决方案就足够了,并且提供了灵活性,如上所述。
我看到很多关于 Facebook 如何按其规模管理数据的问题。答案几乎总是:“他们做什么并不重要,因为你永远不必按照他们的规模去做他们所做的事情。”