模型中许多空-外键的成本是多少?

时间:2019-07-11 05:48:44

标签: django django-models

我有一个Post模型,一个Image模型和一个Channel模型。我在连接到Post模型的Image模型中有一个外键。此外,我试图添加连接到Channel模型的可为空的外键。

   class Image(models.Model):
        post = models.ForeignKey(Post, null=True, blank=True, on_delete=models.CASCADE)
        comment = models.ForeignKey(Comment, null=True, blank=True, on_delete=models.CASCADE)
        news = models.ForeignKey(News, null=True, blank=True, on_delete=models.CASCADE)
        message = models.ForeignKey(Message, null=True, blank=True, on_delete=models.CASCADE)

        channel = models.ForeignKey(Channel, null=True, blank=True, on_delete=models.CASCADE)
        file = ProcessedImageField(upload_to='uploads/%Y/%m/%d/',
                                    processors=[Transpose()],
                                    format='JPEG',
                                    options={'quality': 50},
                                    blank=True)

我担心的是,频道字段几乎为空,因为每个频道只需要一张图片。但是图像必须与Post相关联。因此,每个频道都有一个与帖子相关的图片。但是,发布的帖子和图片将比频道多得多,因此Image模型中的频道字段将大部分时间被浪费。

我想到的另一个解决方案是专门为Channel模型创建一个新的图像模型,并在创建新的图像实例时,手动从原始的图像发布后连接的实例中复制图像。

class ChannelImage(models.Model):
            channel = models.OneToOneField(Channel)
            post = models.OneToOneField(Post)
            file = ProcessedImageField(upload_to='uploads/%Y/%m/%d/',
                                        processors=[Transpose()],
                                        format='JPEG',
                                        options={'quality': 50},
                                        blank=True)
//copy a file from the original post

所以我的问题是,在模型中浪费这么多空null外键的代价是多少?在模型中有很多浪费的外键可以吗?

2 个答案:

答案 0 :(得分:2)

首先

拥有很多行中具有null值的属性的模型在技术上并没有什么坏处。

关于您的设计

您谈论两种设计:

Image -> Channel  ( image references channel )
ChannelImage -> Image ( new model to store  channel image )

但是,在您的帖子中,您说:

  

因此,每个频道都有一个与帖子相关的图片。

但是,怎么了?

Channel -> Image ( channel reference image )

使用这种方法,您不会丢失任何信息,因为Image仍与Post连接。

答案

我认为是这样的:

  1. database normalization应用于您的方案。
  2. 将自然键更改为Surrogate keys(编号)。也许您想保留一些自然键。
  3. 检查您的设计是否存在性能问题(也许您需要在字段中汇总一些数据才能更快地进行一些查询)。空值不是性能问题。

奖金轨道

自django 2.2起,您可以编写index condition,这意味着,如果需要通过具有大量null的属性为模型建立索引,则可以根据需要仅对具有某些值的行进行索引此属性,例如不为null。

  

如果表很大,并且您的查询主要针对行的子集,则将索引限制为该子集可能很有​​用。将条件指定为Q。例如,condition = Q(pages__gt = 400)索引具有400页以上的记录。

答案 1 :(得分:0)

在考虑成本时,您需要考虑两个主要方面;时间和记忆。

关于Postgresql的外键成本有一个不错的post。在只有一个动态参数的情况下,执行了有关外键对时间性能的影响的测试。结果如下:

  

此函数接受的唯一参数是应创建的引用此源表的表数量。这些计时被收集了好几次,分别在三轮运行后平均为2961毫秒,3805毫秒,4606毫秒,5089毫秒和5785毫秒。我们可以看到,仅使用五个外键,我们的更新性能下降了28.5%。到我们有20个外键时,更新速度降低了95%!

考虑内存成本时,考虑到当今的计算机,这并没有多大关系。但是,如果您认为将有很多空的外键字段,则可以考虑创建一个交集表而不是使用外键。