【问题标题】:What is the cost of many null-foreign keys in a model?模型中许多空外键的成本是多少?
【发布时间】:2019-07-11 05:48:44
【问题描述】:

我有一个 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)

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

我想到的另一个解决方案是专门为 Channel 模型创建一个新的图像模型,当创建新的图像实例时,手动从原始的 image-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

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

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    首先

    在很多行中有一个具有空值属性的模型在技术上没有什么不好的。

    关于您的设计

    你谈了两种设计:

    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(ID)。也许您想保留一些自然键。
    3. 检查您的设计是否存在性能问题(也许您需要在字段中聚合一些数据以使某些查询更快)。空值不是性能问题。

    奖励曲目

    从 django 2.2 开始,您可以编写 index condition,这意味着,如果您需要通过具有大量空值的属性来索引模型,您可以根据需要仅对在该属性上具有某些值的行进行索引,比如不为空。

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

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-08
        • 2015-01-29
        • 2021-10-31
        • 2012-05-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多