我所知道的所有流行的SQL数据库都通过索引来有效地实现外键。
假设N:1关系学生 - >学校,学校ID存储在学生表中,带有(有时是可选的)索引。对于一个特定的学生,你可以找到他们的学校只是查找该行中的学校ID,对于一个特定的学校,你可以通过在学生的外键中查找索引中的学校ID来找到它的学生。关系数据库101。
但这是唯一明智的实施吗?想象一下,您是数据库实现者,而不是在外键列上使用btree索引,而是在关系的另一(多)端的行上添加(对用户不可见)集。因此,不是在学生中索引学校ID列,而是有一个不可见的列,它是学校行本身的一组学生ID。然后,为特定学校提取学生是一个简单的迭代集。这种实施是不常见的原因吗?是否存在一些无法以这种方式有效支持的查询?这两种方法似乎或多或少等同,以特定的实现细节为模。在我看来,你可以模仿另一个解决方案。
在我看来,它在概念上与分裂btree相同,后者包含(school_id,student_row_id)的排序运行,并将每次运行存储在学校行本身。在学校主键中查找学校ID可以为您提供学生ID,就像查找外键索引中的学校ID一样。
为清晰起见,已修改
答案 0 :(得分:3)
您似乎建议将“逗号分隔的值列表”存储为表格的字符列中的字符串。而且你说它“就像迭代集合一样简单”。
但是在关系数据库中,当它作为列中的值列表存储时,“迭代集合”并不简单。也没有效率。它也不符合关系模型。
考虑将成员添加到集合或从集合中删除,或者甚至仅确定成员是否在集合中时所需的操作。考虑强制执行完整性所需的操作,以验证该“逗号分隔列表”中的每个成员是否有效。关系数据库引擎不会帮助我们解决这个问题,我们必须自己编写所有代码。
乍一看,这个想法似乎是一个很好的方法。而且完全有可能做到,并使一些代码工作。但是,一旦我们超越了琐碎的示范,进入真实问题和现实世界数据量的领域,事实证明这是一个非常非常糟糕的想法。存储逗号分隔列表是非常熟悉的SQL反模式。
我强烈推荐Bill Karwin的优秀书籍第2章:SQL Antipatterns: Avoiding the Pitfalls of Database Programming ISBN-13:978-1934356555
(这里的讨论涉及“关系数据库”以及它是如何设计的,遵循关系模型,由Ted Codd和Chris Date开发的理论。)
“所有非密钥列都依赖于密钥,整个密钥,除了密钥之外什么都没有。所以请帮助我Codd。”
问:这种实施是不是很常见?
是的,这种情况并不常见,因为它面对关系理论。它使一个简单的问题(对于关系模型)成为一个混乱的混乱,关系数据库无法帮助我们。如果我们存储的只是一串字符,并且数据库永远不需要对它做任何事情,除了存储字符串并检索字符串之外,我们会很好。但我们不能要求数据库将其解释为代表实体之间的关系。
问:是否存在一些无法以这种方式有效支持的查询?
任何需要将“值列表”转换为要返回的行集的查询都是低效的。任何需要识别包含特定值的“值列表”的查询都是低效的。从“值列表”中插入或删除值的操作效率很低。
答案 1 :(得分:2)
这可能会在一小部分情况下为您带来一些小的好处。但缺点很多。
GROUP BY
FK列,或者将其加入临时表/子查询/ CTE;所有这些情况都可能受益于索引的存在,但没有一个查询涉及父表。我可以继续。在许多这些案例中可能存在缓解因素或明显的解决方案(更不用说我本身的直接误解),尽管我可能忽略了许多问题。无论如何,我很满意他们已经很好地想到了这一点......