多对多关系 - 大表的查询性能

Posted

技术标签:

【中文标题】多对多关系 - 大表的查询性能【英文标题】:Many-to-Many Relationship - Query Performance with large table sizes 【发布时间】:2012-07-30 22:09:10 【问题描述】:

假设这是我的架构:

class modelA(models.Model):
  b = models.ManyToManyField(through='linkModel')

class modelB(models.Model):
  name = models.CharField()

class linkModel(models.Models):
  a = models.ForeignKey(modelA)
  b = models.ForeignKey(modelB)
  (other link-relevant stuff)

在查找链接到 A 的 B 实例时,我可能会遇到查询性能问题,反之亦然。 100,000 行?百万?

使用单个 ForeignKey 关系而不是 ManyToMany(在某些情况下可能重新排列架构)会提供更好的性能吗?

【问题讨论】:

【参考方案1】:

根据我不熟悉的框架的行为,连接可能会传递到后备数据库服务器以执行。如果是这样,那么你会发现索引效率是 O(log n) 并且阻塞点不是连接而是结果集的大小。

假设有能力的架构设计和索引,批量数据操作性能总是受工作集大小的限制。

要获得适用于您的数据库服务器、框架和应用程序逻辑的特定组合的明确答案,您将不得不执行测试,这可能与现代实践完全脱节。

您不一定需要使用大型复杂应用程序进行测试。您可以将有趣的应用程序代码摘录到测试应用程序中。您需要大量数据。

如果您希望有人已经测试过您的特定场景,那么您需要详细描述您的配置。您已经提供了示例应用程序逻辑,这是一个好的开始。

可以干扰的事物数量惊人。例如,在 Microsoft SQL Server 2008 数据库上打开 Auto-shrink 选项会产生巨大的开销,并将 TPM 数字减少大约 3 倍。您必须找到并记录这些内容。

【讨论】:

【参考方案2】:

除了Peter Wone said之外,这里是数据库中应该存在的“理想”联结表结构,以便JOIN的两个“方向”以最佳方式执行:

具有由 2 个 FK 组合而成的复合 PK。 具有与 PK 完全“反向”的备用索引。 两个索引(主索引和备用索引)都经过压缩,以最大限度地减少重复前沿字段的开销。 没有代理键(因此我们不需要第三个索引)。 是clustered。由于备用索引已经包含所有 PK 字段(只是以相反的顺序),因此通常没有与聚簇表中的备用索引相关的开销。并且由于它是covers JOIN,所以没有双重查找。

Oracle 的语法如下所示:

CREATE TABLE LINK_MODEL (
    MODEL_A_ID INT,
    MODEL_B_ID INT,
    PRIMARY KEY (MODEL_A_ID, MODEL_B_ID),
    FOREIGN KEY (MODEL_A_ID) REFERENCES MODEL_A (MODEL_A_ID),
    FOREIGN KEY (MODEL_B_ID) REFERENCES MODEL_B (MODEL_B_ID)
) ORGANIZATION INDEX COMPRESS;

CREATE INDEX LINK_MODEL_IE1 ON LINK_MODEL (MODEL_B_ID, MODEL_A_ID) COMPRESS;

这样,查询给定 A 的 B 只需要对索引 LINK_MODEL 进行简单的范围扫描,无需任何表堆访问(根本没有表堆)。查询给定 B 的 As 需要对 LINK_MODEL_IE1 进行简单的范围扫描,也不需要任何表堆访问。

遗憾的是,并非所有数据库都支持集群和索引压缩,但您应该在 DBMS 和 ORM 允许的范围内尽可能多地实现这一点。

【讨论】:

以上是关于多对多关系 - 大表的查询性能的主要内容,如果未能解决你的问题,请参考以下文章

MS Access:对多个表的交叉表查询(多对多关系)

mysql - 来自桥接表的多对多查询[关闭]

hibernate关联关系(多对多)

mysql表的一对一/一对多/多对多联系

mybatis11--多对多关联查询

Mysql数据库多对多关系未建新表