sql >> Database teknologi >  >> RDS >> Mysql

Sådan forbedres forespørgselsydeevne i Django admin-søgning på relaterede felter (MySQL)

Efter en masse undersøgelser fandt jeg ud af, at problemet kom fra, hvordan søgeforespørgslen er bygget til admin-søgefeltet (i ChangeList klasse). I en søgning med flere termer (ord adskilt af mellemrum) føjes hvert udtryk til QuerySet ved at sammenkæde et nyt filter() . Når der er et eller flere relaterede felter i search_fields , vil den oprettede SQL-forespørgsel have en masse JOIN lænket efter hinanden med mange JOIN for hvert relateret felt (se min relateret spørgsmål for nogle eksempler og mere info). Denne kæde af JOIN er der således, at hvert udtryk kun søges i delmængden af ​​datafilteret efter det foregående udtryk OG, vigtigst af alt, at et relateret felt kun behøver at have én term (i forhold til at skulle have ALLE termer) for at kunne matche. Se Omspændende relationer med flere værdier i Django-dokumenterne for mere information om dette emne. Jeg er ret sikker på, at det er den adfærd, der oftest er ønsket for admin-søgefeltet.

Ulempen ved denne forespørgsel (med relaterede felter involveret) er, at variationen i ydeevne (tid til at udføre forespørgslen) kan være virkelig stor. Det afhænger af mange faktorer:antal søgte termer, søgeord, type feltsøgning (VARCHAR osv.), antal feltsøgninger, data i tabellerne, tabellernes størrelse osv. Med den rigtige kombination er det nemt at have en forespørgsel, der for det meste vil tage evigheder (en forespørgsel, der tager mere end 10 min. for mig, er en forespørgsel, der tager evigheder i forbindelse med dette søgefelt).

Grunden til, at det kan tage så lang tid, er, at databasen skal oprette en midlertidig tabel for hver term og scanne den for det meste for at søge efter den næste term. Så det lægger sig virkelig hurtigt sammen.

En mulig ændring for at forbedre ydeevnen er at ANDed alle termer i samme filter() . På denne måde vil de kun være én JOIN efter relateret felt (eller 2, hvis det er mange til mange) i stedet for mange flere. Denne forespørgsel vil være meget hurtigere og med meget lille ydeevnevariation. Ulempen er, at relaterede felter skal have ALLE vilkårene for at matche, så du kan få færre matches i mange tilfælde.

OPDATERING

Som spurgt af trinchet her er hvad der er nødvendigt for at ændre søgeadfærden (for Django 1.7). Du skal tilsidesætte get_search_results() af de admin-klasser, hvor du ønsker denne form for søgning. Du skal kopiere al metodekoden fra basisklassen (ModelAdmin ) til din egen klasse. Så skal du ændre disse linjer:

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

Til det:

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

Denne kode er ikke testet. Min originale kode var til Django 1.4, og jeg tilpasser den bare til 1.7 her.



  1. group_concat og hvordan man bruger rækkenummer i sqlite

  2. PHP/MySQL grupperer resultater efter kolonne

  3. SQL Server Geografi datatype nærmeste punkt på linjen

  4. SQL-forespørgsel, der returnerer alle datoer, der ikke er brugt i en tabel