优化我不会使用的主键

时间:2018-07-25 15:29:17

标签: python django postgresql django-models django-orm

我正在创建一个新的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,72op / s使用“全部删除并创建”方法,我希望这些数字在我们的生产服务器上会更高)。 但是我担心也很快达到自动递增上限(似乎大约一年)。

我想象的其他可能性:

  • 使用Bigint主键:可以,但是效果可能不太好,尤其是考虑到我永远不会使用该主键(并且BigAutoField直到Django 1.10才可用)
  • 使用UUID主键:相同的内容(UUIDField直到Django 1.8才可用)
  • 使用自定义的CharField主键,类似于"{self.field1.pk}/{self.field2.pk}/{self.field3}",但我什至不知道Django是否可以根据实例本身来处理主键生成器(虽然优点是即使在nullfield2上使用field3值也可以确保唯一性)

您的建议是什么(除了升级到较新版本的Django,我知道我来晚了...)?您是否认为我正在寻找太多优化?

堆栈:

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

1 个答案:

答案 0 :(得分:1)

如果您喜欢冒险,可以尝试将id列变成没有默认值的可空整数列。

注意:这将破坏Model 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具有三个PositiveSmallIntegerFields,而不是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'), )