Медленный ЗАКАЗ ПО ЛИМИТУ

11

У меня есть этот запрос:

SELECT * 
FROM location 
WHERE to_tsvector('simple',unaccent2("city"))
   @@ to_tsquery('simple',unaccent2('wroclaw')) 
order by displaycount

Я рада этому:

"Sort  (cost=3842.56..3847.12 rows=1826 width=123) (actual time=1.915..2.084 rows=1307 loops=1)"
"  Sort Key: displaycount"
"  Sort Method: quicksort  Memory: 206kB"
"  ->  Bitmap Heap Scan on location  (cost=34.40..3743.64 rows=1826 width=123) (actual time=0.788..1.208 rows=1307 loops=1)"
"        Recheck Cond: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"        ->  Bitmap Index Scan on location_lower_idx  (cost=0.00..33.95 rows=1826 width=0) (actual time=0.760..0.760 rows=1307 loops=1)"
"              Index Cond: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"Total runtime: 2.412 ms"

Но когда я добавляю LIMIT, выполнение занимает больше 2 секунд:

SELECT * 
FROM location 
WHERE to_tsvector('simple',unaccent2("city"))
   @@ to_tsquery('simple',unaccent2('wroclaw')) 
order by displaycount 
limit 20

Объясните:

"Limit  (cost=0.00..1167.59 rows=20 width=123) (actual time=2775.452..2775.643 rows=20 loops=1)"
"  ->  Index Scan using location_displaycount_index on location  (cost=0.00..106601.25 rows=1826 width=123) (actual time=2775.448..2775.637 rows=20 loops=1)"
"        Filter: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"Total runtime: 2775.693 ms"

Я думаю, что это проблема с ORDER BY и LIMIT. Как я могу заставить PostgreSQL использовать индекс и выполнить упорядочение в конце?

Подзапрос не помогает:

SELECT * 
FROM (
    SELECT * 
    FROM location 
    WHERE to_tsvector('simple',unaccent2("city"))
       @@ to_tsquery('simple',unaccent2('wroclaw')) 
    order by displaycount
) t 
LIMIT 20;

или:

SELECT * 
FROM (
    SELECT * 
    FROM location 
    WHERE to_tsvector('simple',unaccent2("city"))
       @@ to_tsquery('simple',unaccent2('wroclaw'))
) t 
order by displaycount 
LIMIT 20;
Зири
источник

Ответы:

12

Я предполагаю, что это исправит ваш запрос:

SELECT * 
FROM   location 
WHERE     to_tsvector('simple',unaccent2(city))
       @@ to_tsquery('simple',unaccent2('wroclaw')) 
ORDER  BY to_tsvector('simple',unaccent2(city))
       @@ to_tsquery('simple',unaccent2('wroclaw')) DESC
         ,displaycount 
LIMIT  20;

Я повторяю это WHEREусловие в качестве первого элемента ORDER BYпредложения - которое логически избыточно, но должно удерживать планировщика запросов от предположения, что было бы лучше обрабатывать строки в соответствии с индексом location_displaycount_index- что оказывается намного дороже.

Основная проблема заключается в том, что планировщик запросов явно недооценивает избирательность и / или стоимость вашего WHEREсостояния. Я могу только догадываться, почему это так.

У вас работает автоочистка - которая также должна позаботиться о работе ANALYZEна ваших столах? Таким образом, ваша статистика таблиц актуальна? Любой эффект, если вы запустите:

ANALYZE location;

И попробуй еще раз?

Может также случиться так, что избирательность @@оператора неверно оценена. Я полагаю, что это очень трудно оценить по логическим причинам.


Если мой запрос не должен решить проблему, и, как правило, для проверки основной теории, выполните одно из следующих двух действий :

Последний менее навязчив и влияет только на текущий сеанс. Он оставляет методы bitmap heap scanи bitmap index scanоткрытые, которые используются более быстрым планом.
Затем повторите запрос.

КСТАТИ: Если теория обоснована, ваш запрос (как у вас сейчас) будет намного быстрее с менее избирательным поисковым термином в условиях FTS - вопреки тому, что вы могли ожидать. Попытайся.

Эрвин Брандштеттер
источник
1
Запрос работает. Отключение сканирования индекса тоже работает. АНАЛИЗ не работает. Большое спасибо за исчерпывающий ответ.
Зири
0

При использовании LIMIT postgresql настроить его план будет оптимальным только для извлечения подмножества строки. К сожалению, это как-то делает неправильный выбор в вашем случае. Это может быть потому, что статистика для таблицы слишком старая. Попробуйте обновить статистику, указав местоположение VACUUM ANALYZE;

Принудительное использование индексов обычно выполняется путем запрета использования последовательного сканирования (set enable_seqscan = false). Однако в вашем случае он не выполняет последовательное сканирование, он просто переключается на другой индекс для запроса с LIMIT.

Если анализ не помогает, можете ли вы сказать, какую версию postgresql вы используете? Кроме того, сколько строк в таблице?

Eelke
источник
Анализ не помог. В таблице около 36000 строк, и я использую postgresql 9.1.
Зири