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

Django 模型中许多空外键的成本是多少?,django,django-models,Django,Django Models,我有一个帖子模型、一个图片模型和一个频道模型。我在连接到Post模型的图像模型中有一个外键。此外,我正在尝试添加一个连接到通道模型的可空外键 class Image(models.Model): post = models.ForeignKey(Post, null=True, blank=True, on_delete=models.CASCADE) comment = models.ForeignKey(Comment, null=True, blank

我有一个帖子模型、一个图片模型和一个频道模型。我在连接到Post模型的图像模型中有一个外键。此外,我正在尝试添加一个连接到通道模型的可空外键

   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的图像。但是,与一个通道相比,将有无可比拟的更多帖子和图像,因此图像模型中的通道字段将浪费大部分时间

我想到的另一个解决方案是专门为通道模型创建一个新的图像模型,当创建新的图像实例时,手动从原始图像后连接实例复制图像

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的模型,这在技术上并没有什么不好的

关于你的设计 您将讨论两种设计:

Image -> Channel  ( image references channel )
ChannelImage -> Image ( new model to store  channel image )
但是,在你的帖子中,你说:

因此,每个通道都有一个连接到post的图像

但是,你怎么了

Channel -> Image ( channel reference image )
使用这种方法,您不会丢失信息,因为
Image
仍然连接到
Post

答复 在我看来,这是一种方式:

  • 适用于您的场景
  • 将自然关键点更改为(Id)。也许你想保留一些天然钥匙
  • 检查您的设计是否存在性能问题(可能需要在字段中聚合一些数据以加快查询速度)。空值不是性能问题
  • 奖金轨道 由于django 2.2是可以编写的,这意味着,如果需要通过一个包含大量空值的属性对模型进行索引,那么如果需要的话,可以只对该属性上具有某些值的行(如not null)进行索引

    如果表非常大,并且您的查询主要针对行的子集,那么将索引限制到该子集可能会很有用。将一个条件指定为Q。例如,条件=Q(pages_ugt=400)索引超过400页的记录


    当考虑成本时,你需要考虑两个主要方面;时间和记忆

    关于postgresql的外键成本有一个很好的解释。在只有一个动态参数的情况下,测试外键对时间性能的影响。结果如下:

    此函数接受的唯一参数是它应该创建的引用此源表的表的数量。[…]多次收集这些计时,每次运行三次后平均为2961ms、3805ms、4606ms、5089ms和5785ms。正如我们所看到的,在仅仅五个外键之后,我们的更新性能下降了28.5%。当我们有20个外键时,更新速度慢了95%

    当你考虑内存成本时,当你想到今天的计算机时,这并不是什么大问题。但是如果你认为你会有很多空外键字段,你也可以考虑创建一个交叉表,而不是使用外键。