Повільний ЗАМОВЛЕННЯ З ГРОМОМ


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відкритими, які використовуються швидшим планом.
Потім повторно запустіть запит.

BTW: Якщо теорія обгрунтована, ваш запит (як у вас зараз) буде набагато швидшим із менш селективним пошуковим терміном в умовах FTS - всупереч тому, що ви можете очікувати. Спробуй це.


1
Запит працює. Відключення покажчиків покажчиків також працює. АНАЛІЗ не працює. Дуже дякую за вичерпну відповідь.
ziri

0

При використанні LIMIT postgresql відрегулюйте, що план буде оптимальним лише для отримання підмножини рядка. На жаль, це якось робить неправильний вибір у вашому випадку. Це може бути тому, що статистика для таблиці занадто стара. Спробуйте оновити статистику, видавши розташування VACUUM ANALYZE;

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

Якщо аналіз не допомагає, чи можете ви сказати, яку версію postgresql ви використовуєте? Також скільки рядків у таблиці?


Аналіз не допоміг. У таблиці розміщено близько 36000 рядків, і я використовую postgresql 9.1.
ziri
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.