Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jak poprawić wydajność zapytań w wyszukiwaniu administracyjnym Django w powiązanych polach (MySQL)

Po wielu badaniach odkryłem, że problem wynika z tego, jak zapytanie jest zbudowane dla pola wyszukiwania administratora (w ChangeList klasa). W wyszukiwaniu wieloterminowym (słowa oddzielone spacją) każdy termin jest dodawany do QuerySetu poprzez łączenie nowego filter() . Gdy istnieje jedno lub więcej powiązanych pól w search_fields , utworzone zapytanie SQL będzie miało dużo JOIN połączone jeden po drugim z wieloma JOIN dla każdego powiązanego pola (zobacz moje powiązane pytanie kilka przykładów i więcej informacji). Ten łańcuch JOIN jest tak, że każdy termin będzie wyszukiwany tylko w podzbiorze filtru danych według terminu poprzedzającego ORAZ, co najważniejsze, aby powiązane pole musiało zawierać tylko jeden termin (w przeciwieństwie do WSZYSTKICH terminów), aby uzyskać dopasowanie. Zobacz Rozpiętość relacji wielowartościowych w dokumentacji Django, aby uzyskać więcej informacji na ten temat. Jestem prawie pewien, że jest to zachowanie pożądane przez większość czasu w polu wyszukiwania administratora.

Wadą tego zapytania (z powiązanymi polami) jest to, że różnice w wydajności (czas na wykonanie zapytania) mogą być naprawdę duże. Zależy to od wielu czynników:liczby wyszukiwanych terminów, wyszukiwanych terminów, rodzaju wyszukiwania pól (VARCHAR itp.), liczby wyszukiwanych pól, danych w tabelach, wielkości tabel itp. Z odpowiednią kombinacją jest to łatwe mieć zapytanie, które trwa w większości w nieskończoność (zapytanie, które zajmuje mi więcej niż 10 minut, jest zapytaniem, które trwa w nieskończoność w kontekście tego pola wyszukiwania).

Powodem, dla którego może to trwać tak długo, jest to, że baza danych musi utworzyć tabelę tymczasową dla każdego terminu i przeskanować ją głównie w celu wyszukania następnego terminu. Tak więc sumuje się to bardzo szybko.

Możliwa zmiana do zrobienia w celu poprawy wydajności to ORAZ wszystkie terminy w tym samym filter() . W ten sposób ich będzie tylko jedno JOIN według powiązanego pola (lub 2, jeśli jest wiele do wielu) zamiast o wiele więcej. To zapytanie będzie dużo szybsze i będzie miało naprawdę małą zmienność wydajności. Wadą jest to, że powiązane pola będą musiały zawierać WSZYSTKIE terminy do dopasowania, więc w wielu przypadkach możesz uzyskać mniej dopasowań.

AKTUALIZACJA

Zapytany przez trinchet oto, co jest potrzebne do zmiany zachowania wyszukiwania (dla Django 1.7). Musisz zastąpić get_search_results() klas administracyjnych, w których chcesz tego rodzaju wyszukiwania. Musisz skopiować cały kod metody z klasy bazowej (ModelAdmin ) do własnej klasy. Następnie musisz zmienić te linie:

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))

Do tego:

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))

Ten kod nie jest testowany. Mój oryginalny kod był dla Django 1.4 i właśnie zaadaptowałem go tutaj dla wersji 1.7.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL nie używa indeksów z klauzulą ​​WHERE IN?

  2. Instrukcja SQL, aby uzyskać wszystkich klientów bez zamówień

  3. mysql gdzie dokładne dopasowanie

  4. MySQL i NHibernate. Jak naprawić błąd:kolumna „ReservedWord” nie należy do tabeli ReservedWords?

  5. Zaktualizuj jedną tabelę MySQL o wartości z innej