database - 我们如何处理快速增长非常大的交集表?

标签 database database-design

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

最佳答案

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

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

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

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

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

在许多情况下,这些问题的答案将是:两者,是和否,在这种情况下,您的表将类似于以下内容(下面的 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_IE1, EXTRA_DATA:由于二级索引覆盖了额外的数据,所以DBMS在从子到父的方向查询时,可以不触表地获取。主键充当聚类键,因此在从父级查询到子级时,额外的数据自然会被覆盖。

在物理上,您只有两个 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);

请注意,除非指定了 PRIMARY KEY NONCLUSTERED,否则 MS SQL Server 会自动对表进行聚簇。


1 换句话说,您是否只需要获得给定“ parent ”的“ child ”,或者您可能需要获得给定“ parent ”的 parent child 。

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

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

关于database - 我们如何处理快速增长非常大的交集表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13547739/

相关文章:

MySQL - 显示记录及其父项

database - QGIS 和 PGadmin 中多边形的面积大小不同

ruby-on-rails - 在 Rails 中存储/检索历史数据的技术

database-design - 如何在网上商店实现特价商品

database-design - 设计电子商务数据库

mysql - SQL构建双向图

Java 和数据库连接。哪种连接类别更好,为什么?

php - 无法将日期存储在数据库中

mysql - 数据库设计 : Best way to represent checkbox optional items?

mysql - 存储具有不同属性的类似产品