Индекс не используется, когда LIMIT используется в postgres - PullRequest
8 голосов
/ 20 декабря 2011

У меня есть таблица слов с индексом (language_id, state). Вот результаты для EXPLAIN ANALYZE:

Без ограничений

explain analyze SELECT "words".* FROM "words" WHERE (words.language_id = 27) AND (state IS NULL);

Bitmap Heap Scan on words  (cost=10800.38..134324.10 rows=441257 width=96) (actual time=233.257..416.026 rows=540556 loops=1)
Recheck Cond: ((language_id = 27) AND (state IS NULL))
->  Bitmap Index Scan on ls  (cost=0.00..10690.07 rows=441257 width=0) (actual time=230.849..230.849 rows=540556 loops=1)
Index Cond: ((language_id = 27) AND (state IS NULL))
Total runtime: 460.277 ms
(5 rows)

Предел 100

explain analyze SELECT "words".* FROM "words" WHERE (words.language_id = 27) AND (state IS NULL) LIMIT 100;

Limit  (cost=0.00..51.66 rows=100 width=96) (actual time=0.081..0.184 rows=100 loops=1)
->  Seq Scan on words  (cost=0.00..227935.59 rows=441257 width=96) (actual time=0.080..0.160 rows=100 loops=1)
Filter: ((state IS NULL) AND (language_id = 27))
Total runtime: 0.240 ms
(4 rows)

Почему это происходит? Как я могу получить индекс для использования во всех случаях?

Спасибо.

Ответы [ 4 ]

7 голосов
/ 20 декабря 2011

Я думаю, что планировщик запросов PostreSQL просто думает, что во втором случае - в случае с LIMIT - не стоит применять индекс, поскольку [LIMIT] слишком мал.Так что это не проблема.

5 голосов
/ 20 декабря 2011

Ознакомьтесь с документацией PostgreSQL о Использование EXPLAIN и Планирование запросов .Причина, по которой планировщик запросов предпочитает последовательное сканирование по сравнению с индексным сканированием в случае LIMIT 100, заключается просто в том, что последовательное сканирование дешевле.

В запросе нет условия ORDER BY, поэтому планировщикнормально с первыми 100 (случайными) строками, которые соответствуют условию фильтра.Сканирование индекса потребовало бы сначала прочитать страницы индекса, а затем прочитать страницы данных, чтобы получить соответствующие строки.При последовательном сканировании нужно только прочитать страницы данных, чтобы извлечь строки.В вашем случае статистика таблицы предполагает, что имеется достаточно (случайных) строк, соответствующих условию фильтра.Стоимость последовательного чтения страницы, чтобы получить 100 строк, считается дешевле, чем стоимость чтения индекса сначала, а затем извлечения фактических строк.Вы можете увидеть другой план при увеличении лимита или когда меньшее количество строк соответствует условию фильтра.

При настройках по умолчанию планировщик учитывает стоимость случайного чтения страницы ( random_page_cost ) четыреумножить стоимость последовательного чтения страницы ( seq_page_cost ).Эти параметры могут быть скорректированы для настройки планов запросов (например, когда вся база данных находится в ОЗУ, случайное чтение страницы не обходится дороже, чем последовательное чтение страницы, и предпочтительнее сканирование индекса).Вы также можете опробовать различные планы запросов, включив / отключив определенные виды сканирования, например:

set enable_seqscan = [on | off]
set enable_indexscan = [on | off]

Хотя возможно включить / отключить определенные виды сканирования в глобальном масштабе, это следует использовать только для объявлений.HOC для отладки или устранения неполадок для каждого сеанса.

Также запустите VACUUM ANALYZE words перед тестированием планов запросов, в противном случае автоматический вакуум ( autovaccum ), запущенный между тестами, может повлиять на результаты.

3 голосов
/ 20 декабря 2011

Без ограничения: строки = 540556 циклов = 1 Общее время выполнения: 460,277 мс

С ограничением: ряды = 100 циклов = 1 Общее время выполнения: 0,240 мс

Я не вижу здесь проблемы. Если ваш запрос выдает 500 тыс. Строк, ему потребуется больше времени.

0 голосов
/ 20 декабря 2011

Также странно, что два запроса возвращают разное количество строк. Я полагаю, вы вставили хотя ... Хм, а что если вы сделаете дополнительный выбор?

select * from (select ...) limit 100;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...