当没有通过ORM创建行时,Django很慢基于外键删除行

时间:2017-10-17 15:16:03

标签: mysql django django-models orm

我遇到一种情况,当Django通过外键(FK)与另一个表相关但是没有通过Django ORM创建时,从表中删除行的速度很慢。

我有Record的以下Django模型:

class Record(models.Model):

    job = models.ForeignKey(Job, on_delete=models.CASCADE)
    index = models.IntegerField(null=True, default=None)
    record_id = models.CharField(max_length=1024, null=True, default=None)
    document = models.TextField(null=True, default=None)
    error = models.TextField(null=True, default=None)

这与Djano迁移创建后的Job列(MySQL中的job)模型job_id有关。

但是,Record行不是通过Django编写的,而是通过jdbc.write()从Apache Spark编写的。典型示例可能是1 Job,其中包含45k相关Record行。

问题是,虽然通过Django ORM通过Job 删除job.delete()实例删除关联的Record行,但它很慢,5 1 Job为-7秒,关联Record行为45k,160k为20-30秒,等等。

我的理解是Django 模拟 ON DELETE CASCADE以适应不同的DB后端,这是有道理的。但我想知道:如果Record行不是通过Django ORM创建的,那么它是否会绕过某种内部Django索引,否则会更快地级联删除关联的Record行?

Record模型表创建SQL如下所示:

core_record | CREATE TABLE `core_record` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `index` int(11) DEFAULT NULL,
  `record_id` varchar(1024) DEFAULT NULL,
  `document` longtext,
  `error` longtext,
  `job_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `core_record_job_id_8016b123_fk_core_job_id` (`job_id`),
  CONSTRAINT `core_record_job_id_8016b123_fk_core_job_id` FOREIGN KEY (`job_id`) REFERENCES `core_job` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=338041 DEFAULT CHARSET=utf8

正如预期的那样,ON DELETE CASCADE没有job_id。但是,我注意到FK约束有一个奇怪的KEY core_record_job_id_8016b123_fk_core_job_id,我认为可能会建议某种内部Django索引。我的理解是InnoDB引擎自动索引FK关系,但是当Django通过ORM管理表时,不会利用这种可供性。

一种方法似乎可能是将core_record表更改为包含ON DELETE CASCADE的FK,然后指示Django不执行任何操作on_delete,依赖MySQL删除子行。但我想知道是否有其他选择?我想尽可能避免手动更改表,并允许Django管理SQL迁移。

如果Django确实对FK有某种内部索引,那么当ORM没有创建行时,有没有办法在Django中索引数据库/表行?

非常感谢任何建议或见解。

1 个答案:

答案 0 :(得分:0)

结束在Django上下文之外创建表,但仍然在Django中包含一个用于检索记录的模型,并在必要时进行更新。

模型看起来如此,显着位为managed = False

class Record(models.Model):

    '''
    DB model for individual records.
    Note: This DB model is not managed by Django.
    '''

    job = models.ForeignKey(Job, on_delete=models.CASCADE)
    index = models.IntegerField(null=True, default=None)
    record_id = models.CharField(max_length=1024, null=True, default=None)
    document = models.TextField(null=True, default=None)
    error = models.TextField(null=True, default=None)

    # this model is managed outside of Django
    class Meta:
        managed = False

在一些初步测试中,当依赖于MySQL内置索引和ON DELETE CASCADE设置时,使用FK删除150k记录的时间从3-4分钟到几秒钟。非常满意的安排:能够在Django中方便地查询,但是本机MySQL的性能。