Ho ereditato una grande base di codice legacy che viene eseguito in django 1.5 e il mio compito attuale è quello di accelerare una sezione del sito che prende ~ 1min per caricare.Migliorare la velocità di query: SELECT con semplice COME
ho fatto un profilo della app e ottenuto questo:
Il colpevole, in particolare, è la seguente query (messo a nudo per brevità):
SELECT COUNT(*) FROM "entities_entity" WHERE (
"entities_entity"."date_filed" <= '2016-01-21' AND (
UPPER("entities_entity"."entity_city_state_zip"::text) LIKE UPPER('%Atherton%') OR
UPPER("entities_entity"."entity_city_state_zip"::text) LIKE UPPER('%Berkeley%') OR
-- 34 more of these
UPPER("entities_entity"."agent_city_state_zip"::text) LIKE UPPER('%Atherton%') OR
UPPER("entities_entity"."agent_city_state_zip"::text) LIKE UPPER('%Berkeley%') OR
-- 34 more of these
)
)
che consistono sostanzialmente in un grande come query su due campi, entity_city_state_zip
e agent_city_state_zip
che sono campi character varying(200) | not null
.
Che query viene eseguita due volte (!), Prendendo 18814.02ms ogni volta, e ancora una volta si sostituisce la COUNT
per un SELECT
riprendendo un extra 20216.49
(ho intenzione di memorizzare nella cache il risultato della COUNT
)
La spiegare assomiglia a questo:
Aggregate (cost=175867.33..175867.34 rows=1 width=0) (actual time=17841.502..17841.502 rows=1 loops=1)
-> Seq Scan on entities_entity (cost=0.00..175858.95 rows=3351 width=0) (actual time=0.849..17818.551 rows=145075 loops=1)
Filter: ((date_filed <= '2016-01-21'::date) AND ((upper((entity_city_state_zip)::text) ~~ '%ATHERTON%'::text) OR (upper((entity_city_state_zip)::text) ~~ '%BERKELEY%'::text) (..skipped..) OR (upper((agent_city_state_zip)::text) ~~ '%ATHERTON%'::text) OR (upper((agent_city_state_zip)::text) ~~ '%BERKELEY%'::text) OR (upper((agent_city_state_zip)::text) ~~ '%BURLINGAME%'::text)))
Rows Removed by Filter: 310249
Planning time: 2.110 ms
Execution time: 17841.944 ms
ho provato con un indice su entity_city_state_zip
e agent_city_state_zip
utilizzando variou s combinazioni come:
CREATE INDEX ON entities_entity (upper(entity_city_state_zip));
CREATE INDEX ON entities_entity (upper(agent_city_state_zip));
o utilizzando varchar_pattern_ops
, senza fortuna.
il server utilizza qualcosa di simile:
qs = queryset.filter(Q(entity_city_state_zip__icontains = all_city_list) |
Q(agent_city_state_zip__icontains = all_city_list))
per generare quella query.
Non so che altro per provare,
Grazie!
'query LIKE', che inizia con' '% ...' 'non userà alcun indice btree (compreso' xxx_pattern_ops'). Questi indici sono stati selezionati solo se il modello corrisponde all'inizio. (per esempio 'col LIKE 'XXX%'' o 'col ~ '^ XXX''). Puoi provare il [modulo '' pg_trgm'] (http://www.postgresql.org/docs/current/static/pgtrgm.html), [che fornisce un indice adatto per te] (http: //dba.stackexchange. com/domande/10694/pattern-matching-con-like-simile-a-o-regolari-espressioni-in-PostgreSQL/10696). (ed è possibile usare 'ilike' invece di' like' & 'lower()'/'upper()' chiamate). – pozs
@pozs Non lo sapevo! Proverò a provare – NicoSantangelo
Vorrei almeno sapere quale effetto stava avendo il 'Seq Scan' e se una scansione dell'indice potesse essere sostituita. Scopri quale effetto 'set enable_seqscan = false' ha sul piano. DB sta scappando da un SSD? –