Я унаследовал большую устаревшую кодовую базу, которая работает в django 1.5, и моя текущая задача - ускорить раздел сайта, на который требуется загрузить ~ 1min.Улучшение скорости запроса: простой SELECT с LIKE
Я сделал профиль приложения и получил это:
Преступника, в частности, следующий запрос (раздел для краткости):
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
)
)
, которые в основном состоят на большой как запрос на два полей, entity_city_state_zip
и agent_city_state_zip
которые character varying(200) | not null
полей.
Этот запрос выполняется дважды (!), С 18814.02ms каждый раз, и один больше времени Замена COUNT
для SELECT
занимая дополнительное 20216.49
(я собираюсь кэшировать результат COUNT
)
Explain, выглядит так:
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
Я попытался с помощью индекса на entity_city_state_zip
и agent_city_state_zip
с использованием различн s:
CREATE INDEX ON entities_entity (upper(entity_city_state_zip));
CREATE INDEX ON entities_entity (upper(agent_city_state_zip));
или с использованием varchar_pattern_ops
, не повезло.
Сервер использует что-то вроде этого:
qs = queryset.filter(Q(entity_city_state_zip__icontains = all_city_list) |
Q(agent_city_state_zip__icontains = all_city_list))
для создания этого запроса.
Я не знаю, что еще попробовать,
Спасибо!
'LIKE' запросов, который начинается с' '% ...' 'не будет использовать любой индекс ВТКЕЕ (включая 'xxx_pattern_ops'). Эти индексы выбирались только в том случае, если шаблон совпадает с началом. (f.ex. 'col LIKE 'XXX%'' или 'col ~ '^ XXX''). Вы можете попробовать ['pg_trgm' module] (http://www.postgresql.org/docs/current/static/pgtrgm.html), [который предоставляет подходящий вам индекс] (http: //dba.stackexchange. ком/вопросы/10694/шаблон сопоставление с подобным автомодельными к или-регулярным выражениям-в-PostgreSQL/10696). (и вы можете использовать 'ilike' вместо' like' и 'lower()'/'upper()' вызовов). – pozs
@pozs Я этого не знал! Я дам ему попробовать – NicoSantangelo
Я бы хотя бы хотел знать, какое влияние оказал «Seq Scan», и можно ли заменить индексное сканирование. Посмотрите, какой эффект «set enable_seqscan = false» имеет в плане. Разве БД работает от SSD? –