多对多关系 - 大表的查询性能
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 允许的范围内尽可能多地实现这一点。
【讨论】:
以上是关于多对多关系 - 大表的查询性能的主要内容,如果未能解决你的问题,请参考以下文章