2017-05-09 3 views
3

Ich habe 2 verwandte Modelle mit 10 Millionen Zeilen je und will eine effiziente paginierte Anfrage von 50 000 Stück von einem von ihnen und dem Zugang bezogenen Daten auf dem anderen auszuführen:Django: Wie effektiv select_related() mit Paginator verwenden?

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) 

Wie Sie sehen, können RnaPrecomputed bezieht sich auf RNA über einen Fremdschlüssel. Jetzt möchte ich eine bestimmte Seite von 50 000 Artikeln von RnaPrecomputed und entsprechenden Rna s bezogen auf sie beziehen. Ich erwarte N + 1 Anfragen Problem, wenn ich dies ohne select_related() Anruf mache. Hier sind die Timings:


Zuerst Referenz werde ich nicht das entsprechende Modell berühren überhaupt:

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

Takes:

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

Nun, ich Versuchen Sie, auf Daten zu verwandten Modellen zuzugreifen:

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

es braucht:

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

was viel ist, so, wahrscheinlich habe ich N + 1-Anfragen Problem.


Aber jetzt, wenn ich 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) 

dauert es noch mehr:

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

Also, irgendwie select_related() Dinge 3 mal langsamer gemacht, anstatt sie schneller zu machen. Und wahrscheinlich ohne es, ich habe N + 1 Anfragen, so für jeden Eintrag von RnaPrecomputed, muss Django ORM wahrscheinlich eine zusätzliche Anfrage an die Datenbank zu holen, um die entsprechenden Rna?

Was mache ich falsch und wie macht man select_related() mit paginiertem Queryset gut?

+0

Es wäre nützlich zu sehen, was die Abfragen sind und wie lange sie dauern, anstatt die Gesamtzeit. – Alasdair

+0

@Alasdair Danke für Interesse. Ich bin bereit, Informationen zur Verfügung zu stellen, die Sie verlangen, aber nicht sicher, was Sie genau meinen. Sprechen Sie über SQL-Anfragen? –

+1

Ja, die SQL-Abfragen. Sie können hierfür die Django Debug-Symbolleiste oder 'connection.queries' verwenden. – Alasdair

Antwort

1

Es sollte überprüft werden, dass kein Index in Ihrer Datenbank fehlt. Sie haben db_index=True für das Feld Rna.upi, aber sind Sie sicher, dass der Index in der Datenbank existiert?

Wenn die select_related die count() Abfrage langsam macht, dann könnten Sie versuchen, die select_related auf der paginierten object_list zu tun.

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