【问题标题】:How can we deal with intersection tables that quickly grow very large?我们如何处理快速增长到非常大的交集表?
【发布时间】:2012-11-25 16:31:56
【问题描述】:

例如,我们有表 A 和表 B,它们具有多对多的关系。一个交集表,表 C 存储 A.id 和 B.id 以及表示两者之间关系的值。或者作为一个具体的例子,想象有一个用户帐户、一个论坛和一个业力分数的 stackexchange。或者,学生、课程和成绩。如果表 A 和 B 非常大,表 C 可以并且可能会非常快速地增长(实际上让我们假设它确实如此)。我们该如何处理这样的问题?有没有更好的方法来设计表格来避免这种情况?

【问题讨论】:

  • 你能发布一个模式和一些示例元组吗?

标签: database database-design


【解决方案1】:

没有魔法。如果某些行是连接的,而有些行没有连接,则必须以某种方式表示此信息,并且执行此操作的“关系”方式是“联结”(又称“链接”)表。是的,联结表可以变大,但幸运的是数据库非常有能力处理大量数据。

使用联结表而不是逗号分隔列表(或类似列表)有充分的理由,包括:

  • 高效查询(通过索引和集群)。
  • 参照完整性的实施。

在设计联结表时,请提出以下问题:

  1. 我需要只查询一个方向还是两个方向?1
    • 如果一个方向,只需在两个外键上创建一个复合主键(我们称它们为 PARENT_ID 和 CHILD_ID)。顺序很重要:如果从父级查询到子级,PK 应该是:{PARENT_ID, CHILD_ID}。
    • 如果两个方向,还以相反的顺序创建复合索引,在本例中为 {CHILD_ID, PARENT_ID}。
  2. “额外”数据是否很小?
    • 如果cluster 表和cover 二级索引中的额外数据是必要的。2
    • ,不要对表进行聚类,也不要覆盖二级索引中的多余数据。3
  3. 是否有任何其他表可以将联结表用作父表?
    • 如果,请考虑添加代理键是否值得让子 FK 保持苗条。但请注意,如果您添加代理键,这可能会消除集群的机会。

在许多情况下,这些问题的答案将是:两者,是和否,在这种情况下,您的表将与此类似(Oracle 语法如下):

CREATE TABLE JUNCTION_TABLE (
    PARENT_ID INT,
    CHILD_ID INT,
    EXTRA_DATA VARCHAR2(50),
    PRIMARY KEY (PARENT_ID, CHILD_ID),
    FOREIGN KEY (PARENT_ID) REFERENCES PARENT_TABLE (PARENT_ID),
    FOREIGN KEY (CHILD_ID) REFERENCES CHILD_TABLE (CHILD_ID)
) ORGANIZATION INDEX COMPRESS;

CREATE UNIQUE INDEX JUNCTION_TABLE_IE1 ON
    JUNCTION_TABLE (CHILD_ID, PARENT_ID, EXTRA_DATA) COMPRESS;

注意事项:

  • ORGANIZATION INDEX:大多数 DBMS 称为集群的特定于 Oracle 的语法。其他 DBMS 有自己的语法,有些(MySQL/InnoDB)暗示集群,用户无法关闭它。
  • COMPRESS:一些 DBMS 支持 leading-edge index compression。由于聚簇表本质上是一个索引,因此也可以对其应用压缩。
  • JUNCTION_TABLE_IE1EXTRA_DATA:由于二级索引覆盖了多余的数据,所以DBMS在从child到parent的方向查询时不用碰表就可以拿到。主键充当聚类键,因此在从父级向子级查询时自然会覆盖额外的数据。

实际上,您只有两个 B 树(一个是聚簇表,另一个是二级索引),根本没有表堆。这转化为良好的查询性能(父到子和子到父方向都可以通过简单的索引范围扫描来满足)和插入/删除行时相当小的开销。

这是等效的 MS SQL Server 语法(无索引压缩):

CREATE TABLE JUNCTION_TABLE (
    PARENT_ID INT,
    CHILD_ID INT,
    EXTRA_DATA VARCHAR(50),
    PRIMARY KEY (PARENT_ID, CHILD_ID),
    FOREIGN KEY (PARENT_ID) REFERENCES PARENT_TABLE (PARENT_ID),
    FOREIGN KEY (CHILD_ID) REFERENCES CHILD_TABLE (CHILD_ID)
);

CREATE UNIQUE INDEX JUNCTION_TABLE_IE1 ON
    JUNCTION_TABLE (CHILD_ID, PARENT_ID) INCLUDE (EXTRA_DATA);

请注意,MS SQL Server 会自动对表进行集群,除非指定了 PRIMARY KEY NONCLUSTERED


1 换句话说,您是否只需要获取给定“父母”的“孩子”,或者您可能需要获得给定的父母孩子。

2 覆盖允许仅从索引满足查询,并避免在通过聚集表中的二级索引访问数据时需要进行昂贵的双重查找。

3 这样,额外的数据不会重复(这会很昂贵,因为它很大),但是您可以避免双重查找并用(更便宜的)表堆替换它使用权。但是,请注意clustering factor,它会破坏基于堆的表中范围扫描的性能!

【讨论】:

  • 谢谢你,这是一个很好的答案,我很欣赏为后续阅读提供的链接。
猜你喜欢
  • 1970-01-01
  • 2021-06-24
  • 1970-01-01
  • 2015-02-12
  • 2013-06-10
  • 1970-01-01
  • 2022-08-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多