优化一个我不会告诉我们的主键

2024-04-20 00:23:33 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在创建一个新的Django(1.7)模型:

class MyModel(models.Model):

    field1 = models.ForeignKey('OtherModel')
    field2 = models.ForeignKey('AnotherModel', null=True)
    field3 = models.PositiveSmallIntegerField(db_index=True, null=True)

    other_field1 = models.FloatField(default=0, db_index=True)

    class Meta:
        unique_together = (('field1', 'field2', 'field3'), )

理想情况下,我希望它有元组(field1field2field3)作为主键,但是that's not possible at the moment。 因此,我有一个自动生成并递增的id列,这是Django所要求的,但对我的代码的其余部分完全没有用。你知道吗

我希望能够经常(几乎连续地)删除和重新创建这个模型的实例。 出于性能方面的考虑,我希望避免使用create_or_update方法,因为从我测试的方法来看,删除和创建要快得多(使用create_or_update方法的速度是18op/s,使用“delete all and create”方法的速度是72op/s,我希望在我们的生产服务器上这些数字会更高)。 但我恐怕很快(似乎一年左右)也会达到自动增量上限。你知道吗

我想象的其他可能性:

  • 使用Bigint主键:这样可以,但效果可能不太好,特别是考虑到我永远不会使用这个主键(而且^{}在django1.10之前是不可用的)
  • 使用UUID主键:相同的东西(在django1.8之前,^{}不可用)
  • 使用一个定制的CharField主键,类似于"{self.field1.pk}/{self.field2.pk}/{self.field3}",但我甚至不知道Django是否可以基于实例本身处理主键生成器(优点是即使在field2field3上有null值,它也能确保唯一性)你知道吗

你有什么建议(除了升级到Django的新版本,我知道我迟到了?你认为我在寻找太多的优化吗?你知道吗

堆栈:

  • Django 1.7(暂时无法升级)
  • PostgreSQL 9.6版

Tags: django方法模型selftruedbmodelscreate
1条回答
网友
1楼 · 发布于 2024-04-20 00:23:33

如果您有冒险精神,可以尝试将id列转换为不带默认值的可为空整数列。你知道吗

注意:这将破坏部分模型API、管理和最有可能导致各种不可预见的麻烦,但根据您的用例,它可能只是做您想要的事情。我不是说这是个好主意,我只是给你展示一下选择。你知道吗

也就是说,这是必要的迁移:

migrations.RunSQL([
    "ALTER TABLE myapp_mymodel DROP CONSTRAINT myapp_mymodel_pkey",
    "ALTER TABLE myapp_mymodel ALTER COLUMN id drop default",
    "ALTER TABLE myapp_mymodel ALTER COLUMN id drop not null"]
),

仍然可以创建新对象并获取现有对象,但不能直接保存或删除对象:

>>> m = MyModel.objects.create(field1=1, field2=2, field3=3)
>>> m
<MyModel: MyModel object (None)>
>>> m.delete()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File ".../lib/python3.6/site-packages/django/db/models/base.py", line 886, in delete
    (self._meta.object_name, self._meta.pk.attname)
AssertionError: MyModel object can't be deleted because its id attribute is set to None.

但是,您可以使用.filter(...).delete().filter(...).update(...)

>>> MyModel.objects.filter(field1=1, field2=2, field3=3).update(field3=4)
1
>>> MyModel.objects.filter(field1=1, field2=2, field3=4).delete()
(1, {'myapp.MyModel': 1})

我用来测试这个行为的MyModel有三个阳性的malintegerfields,而不是ForeignKeys,但这不会有什么区别:

class MyModel(models.Model):

    field1 = models.PositiveSmallIntegerField()
    field2 = models.PositiveSmallIntegerField()
    field3 = models.PositiveSmallIntegerField(db_index=True, null=True)

    other_field1 = models.FloatField(default=0, db_index=True)

    class Meta:
        unique_together = (('field1', 'field2', 'field3'), )

相关问题 更多 >