2017-07-13 3 views
0

Was ist der schnellste Weg, um einen Datensatz aus der Datenbank abzufragen, die meine Filterabfrage erfüllt.Django: Schnellster Weg zur zufälligen Abfrage eines Datensatzes mit Filter

mydb.objects.filter(start__gte='2017-1-1', status='yes').order_by('?')[:1] 

wird diese Aussage zunächst Tausende von Datensätzen abfragen und dann eine Auswahl, und es ist sehr langsam, aber ich brauche nur eine, ein gelegentliches. Was ist der schnellste zu bekommen?

+0

Es ist mir egal, was ich ergreife, ich brauche eine zufällige. Es kann nicht immer die gleiche sein. – jifferent

Antwort

1

Nun, ich bin nicht sicher, ob Sie in der Lage sein werden, genau das zu tun, was Sie wollen. Vor ein paar Monaten stieß ich auf ein ähnliches Problem und am Ende habe ich meine Implementierung meines Backends neu gestaltet, damit es funktioniert.

Im Wesentlichen möchten Sie die Abfragezeit verkürzen, indem Sie einen zufälligen Datensatz wählen, der beide Anforderungen erfüllt (start__gte='2017-1-1', status='yes'), aber wie Sie sagen, um die Abfrage zu tun, muss es Ihre gesamte Datenbank filtern. Dies bedeutet, dass Sie keinen "echten" Zufallsdatensatz aus der Datenbank erhalten können, der die Filteranforderungen erfüllt, da die Filterung inhärent alle Ihre Datensätze durchsuchen muss (sonst wäre es nicht wirklich zufällig, wäre es nur) die erste findet, die Ihre Anforderungen erfüllt).

Ziehen Sie stattdessen in Betracht, alle Datensätze mit einer status='yes' in eine separate Beziehung zu versetzen, damit Sie einen zufälligen Datensatz von dort ziehen und mit der größeren Beziehung verknüpfen können. Das würde die Abfragezeit erheblich beschleunigen (und es ist die Art von Lösung, die ich implementiert habe, damit mein Code funktioniert).

Wenn Sie wirklich einen zufälligen Datensatz mit den richtigen Filterinformationen möchten, müssen Sie möglicherweise einige verworrene Mittel verwenden.

Sie könnten eine custom manager in Django verwenden, um es nur einen zufälligen Datensatz, so etwas wie dieses haben zu finden:

class UsersManager(models.Manager): 
    def random(self): 
     count = self.aggregate(count=Count('id'))['count'] 
     random_index = randint(0, count - 1) 
     return self.all()[random_index] 

class User(models.Model): 
    objects = UsersManager() 
    #Your fields here (whatever they are, it seems start__gte and status are some)! 
    objects = UserManager() 

die Sie dann unter Verwendung von nur aufrufen können:

User.objects.random() 

Dies könnte Wiederholen Sie dies mit einem Check in Ihrem Code, bis ein zufälliger Datensatz zurückgegeben wird, der Ihren Anforderungen entspricht. Ich glaube nicht, dass dies unbedingt der sauberste oder programmatisch korrekte Weg ist, dies zu implementieren, aber ich glaube nicht, dass es eine schnellere Lösung für Ihr spezifisches Problem gibt.

Ich habe this site als Quelle für diese Antwort verwendet, und es hat viel mehr solide Informationen über die Verwendung dieser benutzerdefinierten zufälligen Methode! Wahrscheinlich müssen Sie den benutzerdefinierten Manager ändern, um Ihre eigenen Anforderungen zu erfüllen. Wenn Sie jedoch die Methode random() zu Ihrem vorhandenen benutzerdefinierten Manager hinzufügen, sollte er in der Lage sein, das zu tun, was Sie davon brauchen!

Hoffe es hilft!

+1

Danke, ein echter Zufall wäre wirklich schwer in meinem Design, und order_by ('?') Im Django ist wirklich Schmerz in der as. Dies würde mir sehr helfen. – jifferent

2

Die Verwendung von order_by('?') verursacht ein großes Leistungsproblem. Ein besserer Weg ist, so etwas zu verwenden: Getting a random row from a relational database.

count = mydb.objects.filter(start__gte='2017-1-1', status='yes').aggregate(count=Count('id'))['count'] 
random_index = randint(0, count - 1) 
result= mydb.objects.filter(start__gte='2017-1-1', status='yes')[random_index] 
Verwandte Themen