Mysql
 sql >> Datenbank >  >> RDS >> Mysql

So verbessern Sie die Abfrageleistung in der Django-Admin-Suche in verwandten Feldern (MySQL)

Nach vielen Nachforschungen habe ich festgestellt, dass das Problem davon herrührt, wie die Suchabfrage für das Admin-Suchfeld aufgebaut ist (in der ChangeList Klasse). Bei einer Suche mit mehreren Begriffen (Wörter durch Leerzeichen getrennt) wird jeder Begriff dem Abfragesatz hinzugefügt, indem ein neuer filter() verkettet wird . Wenn es ein oder mehrere verwandte Felder in den search_fields gibt , enthält die erstellte SQL-Abfrage viele JOIN hintereinander gekettet mit vielen JOIN für jedes verwandte Feld (siehe meine verwandte Frage für einige Beispiele und weitere Informationen). Diese Kette von JOIN ist da, damit jeder Begriff nur in der Teilmenge des Datenfilters nach dem Präzedenzbegriff gesucht wird UND, was am wichtigsten ist, dass ein verwandtes Feld nur einen Begriff haben muss (statt ALLE Begriffe zu haben), um eine Übereinstimmung zu erzielen. Siehe Mehrwertige Beziehungen aufspannen in der Django-Dokumentation für weitere Informationen zu diesem Thema. Ich bin mir ziemlich sicher, dass es das Verhalten ist, das die meiste Zeit für das Admin-Suchfeld gewünscht wird.

Der Nachteil dieser Abfrage (mit verwandten Feldern) besteht darin, dass die Leistungsschwankungen (Zeit zum Ausführen der Abfrage) sehr groß sein können. Es hängt von vielen Faktoren ab:Anzahl der gesuchten Begriffe, gesuchte Begriffe, Art der Feldsuche (VARCHAR, etc.), Anzahl der Feldsuche, Daten in den Tabellen, Größe der Tabellen, etc. Mit der richtigen Kombination ist es einfach eine Abfrage zu haben, die meistens ewig dauert (eine Abfrage, die mehr als 10 Minuten dauert, ist für mich eine Abfrage, die im Kontext dieses Suchfelds ewig dauert).

Der Grund, warum es so lange dauern kann, ist, dass die Datenbank für jeden Begriff eine temporäre Tabelle erstellen und diese größtenteils vollständig durchsuchen muss, um nach dem nächsten Begriff zu suchen. Das summiert sich also sehr schnell.

Eine mögliche Änderung zur Verbesserung der Leistung ist die UND-Verknüpfung alle Begriffe im gleichen filter() . Auf diese Weise gibt es nur einen JOIN nach verwandtem Feld (oder 2, wenn es viele zu viele sind) anstelle von vielen mehr. Diese Abfrage ist viel schneller und mit wirklich geringen Leistungsschwankungen. Der Nachteil ist, dass in verwandten Feldern ALLE passenden Begriffe vorhanden sein müssen, sodass Sie in vielen Fällen weniger Übereinstimmungen erhalten können.

AKTUALISIEREN

Wie von trinchet gefragt Folgendes ist erforderlich, um das Suchverhalten zu ändern (für Django 1.7). Sie müssen get_search_results() überschreiben der Admin-Klassen, in denen Sie diese Art der Suche wünschen. Sie müssen den gesamten Methodencode aus der Basisklasse kopieren (ModelAdmin ) zu Ihrer eigenen Klasse. Dann müssen Sie diese Zeilen ändern:

for bit in search_term.split():
    or_queries = [models.Q(**{orm_lookup: bit})
                  for orm_lookup in orm_lookups]
    queryset = queryset.filter(reduce(operator.or_, or_queries))

Dazu:

and_queries = []
for bit in search_term.split():
    or_queries = [models.Q(**{orm_lookup: bit})
                  for orm_lookup in orm_lookups]
    and_queries.append(Q(reduce(operator.or_, or_queries)))
queryset = queryset.filter(reduce(operator.and_, and_queries))

Dieser Code ist nicht getestet. Mein ursprünglicher Code war für Django 1.4 und ich passe ihn hier einfach für 1.7 an.