У меня довольно серьезная проблема с производительностью со следующим утверждением, которое я не могу исправить самостоятельно.
Данная ситуация
- У меня есть база данных postgres 8.4 с установленным Postgis 1.4.
- У меня есть геопространственная таблица с ~ 9 миллионами записей. В этой таблице есть столбец геометрии (postgis) и столбец tsvector.
- У меня есть индекс GIST для геометрии и индекс VNAME для столбца vname.
- Таблица
ANALYZE
Я хочу выполнить поиск to_tsquery
text в подмножестве этих геометрий, который должен вернуть мне все затронутые идентификаторы.
Область для поиска ограничит 9 миллионов наборов данных примерно до 100 000, а набор результатов ts_query
внутри этой области, скорее всего, даст результат 0..1000 записей.
Проблема
Анализатор запросов решает, что он хочет сначала выполнить сканирование индекса растрового изображения для vname, а затем объединяет и помещает фильтр в геометрию (и другие условия, которые я имею в этом утверждении).
Вывод анализатора запросов:
Aggregate (cost=12.35..12.62 rows=1 width=510) (actual time=5.616..5.616 rows=1 loops=1)
-> Bitmap Heap Scan on mxgeom g (cost=8.33..12.35 rows=1 width=510) (actual time=5.567..5.567 rows=0 loops=1)
Recheck Cond: (vname @@ '''hemer'' & ''hauptstrasse'':*'::tsquery)
Filter: (active AND (geom && '0107000020E6100000010000000103000000010000000B0000002AFFFF5FD15B1E404AE254774BA8494096FBFF3F4CC11E40F37563BAA9A74940490200206BEC1E40466F209648A949404DF6FF1F53311F400C9623C206B2494024EBFF1F4F711F404C87835954BD4940C00000B0E7CA1E4071551679E0BD4940AD02004038991E40D35CC68418BE49408EF9FF5F297C1E404F8CFFCB5BBB4940A600006015541E40FAE6468054B8494015040060A33E1E4032E568902DAE49402AFFFF5FD15B1E404AE254774BA84940'::geometry) AND (mandator_id = ANY ('{257,1}'::bigint[])))
-> Bitmap Index Scan on gis_vname_idx (cost=0.00..8.33 rows=1 width=0) (actual time=5.566..5.566 rows=0 loops=1)
Index Cond: (vname @@ '''hemer'' & ''hauptstrasse'':*'::tsquery)
что вызывает МНОГО ввода-вывода - AFAIK Было бы разумнее сначала ограничить геометрию, а затем выполнить поиск vname.
Попытки решения
Чтобы добиться желаемого поведения, я попытался
- Поставил геом@@
AREA
в подзапрос -> План выполнения не менял - Я создал временное представление с нужным подмножеством области -> Не изменил план выполнения
- Я создал временную таблицу нужной области -> Создание занимает 4-6 секунд, так что стало еще хуже.
Кстати, извините, что не опубликовал фактический запрос: я думаю, что мой босс действительно разозлится на меня, если я это сделаю, также я ищу больше теоретических указателей для кого-то, чтобы исправить мой фактический запрос. Пожалуйста, спросите, если вам нужны дополнительные разъяснения
ИЗМЕНИТЬ
У Ричарда была очень хорошая мысль: вы можете добиться желаемого поведения планировщика запросов с помощью инструкции width
. Плохо то, что эта временная таблица (или CTE) искажает индекс vname, из-за чего в некоторых случаях запрос ничего не возвращает.
Я смог исправить это, создав новое vname на лету с помощью to_tsvector()
, но это (слишком) дорого — около 300–500 мс на запрос.
Мое решение
Я отказался от поиска vname и пошел с простым LIKE('%query_string%')
(10-20 мс/запрос), но это быстро только в моей среде. YMMV.