2017-05-09 39 views
3

我有2個相關的模型擁有1000萬行,每行和要執行的50 000項其中之一,並獲得相關數據的另一種高效的分頁請求:Django:如何有效地使用select_related()和Paginator?

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相關。現在,我想獲取與他們相關的特定頁面的50000個項目RnaPrecomputed和相應的Rna。我期望N + 1請求的問題,如果我沒有select_related()的呼叫。這裏是計時:


首先,僅供參考我不會接觸到相關的模型都:

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()在分頁查詢集中表現良好?

+0

查看查詢的內容以及查詢時長,而不是整個時間,這將會非常有用。 – Alasdair

+0

@Alasdair感謝您的關注。我願意提供您請求的信息,但不確定,您的意思到底是什麼。你在說SQL請求嗎? –

+1

是的,SQL查詢。您可以使用Django Debug工具欄或'connection.queries'來執行此操作。 – Alasdair

回答

1

值得檢查一下,您不會錯過數據庫中的索引。對於Rna.upi字段,您有db_index=True,但是您確定該索引存在於數據庫中嗎?

如果select_related正在使count()查詢速度慢,那麼你可以嘗試在分頁object_listselect_related

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