我遇到一种情况,当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中索引数据库/表行?
非常感谢任何建议或见解。
答案 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的性能。