Django:如何有效地使用带有Paginator的select_related()?

时间:2017-05-09 10:22:11

标签: sql django orm

我有2个相关模型,每个模型有1000万行,并希望对其中一个项目中的50 000个项目执行有效的分页请求,并在另一个上访问相关数据:

class RnaPrecomputed(models.Model):
    id = models.CharField(max_length=22, primary_key=True)
    rna = models.ForeignKey('Rna', db_column='upi', to_field='upi', related_name='precomputed')
    description = models.CharField(max_length=250)


class Rna(models.Model):
    id = models.IntegerField(db_column='id')
    upi = models.CharField(max_length=13, db_index=True, primary_key=True)
    timestamp = models.DateField()
    userstamp = models.CharField(max_length=30)

如您所见,RnaPrecomputed通过外键与RNA相关。现在,我想获取一个包含50 000项RnaPrecomputed项和与之相关的Rna项的特定页面。如果我没有select_related()调用,我希望N + 1请求有问题。以下是时间安排:

首先,作为参考,我根本不会触及相关模型:

rna_paginator = paginator.Paginator(RnaPrecomputed.objects.all(), 50000)
message = ""
for object in rna_paginator.page(400).object_list:
    message = message + str(object.id)

注意到:

real    0m12.614s
user    0m1.073s
sys 0m0.188s

现在,我将尝试访问相关模型的数据:

rna_paginator = paginator.Paginator(RnaPrecomputed.objects.all(), 50000)
message = ""
for object in rna_paginator.page(400).object_list:
    message = message + str(object.rna.upi)

需要:

real    2m27.655s
user    1m20.194s
sys 0m4.315s

这是很多,所以,可能我有N + 1个请求问题。

但现在,如果我使用select_related()

rna_paginator = paginator.Paginator(RnaPrecomputed.objects.all().select_related('rna'), 50000)
message = ""
for object in rna_paginator.page(400).object_list:
    message = message + str(object.rna.upi)

它需要更多:

real    7m9.720s
user    0m1.948s
sys 0m0.337s

所以,不知怎的select_related()使事情慢了3倍,而不是让它们更快。可能没有它,我有N + 1个请求,因此对于RnaPrecomputed的每个条目,Django ORM可能需要对数据库进行额外请求以获取相应的Rna

我做错了什么以及如何使select_related()在分页查询集中表现良好?

1 个答案:

答案 0 :(得分:1)

值得检查一下,您没有错过数据库中的索引。 db_index=True字段有Rna.upi,但您确定数据库中存在索引吗?

如果select_related使count()查询变慢,那么您可以尝试在分页select_related上执行object_list

for object in rna_paginator.page(300).object_list.select_related():
    message = message + str(object.rna.upi)