Postgresql не использует многостолбцовые индексы (btree_gin)

У меня возникли проблемы с тем, чтобы postgres использовал мои многоколоночные индексы для полного поиска с использованием расширения btree_gin. Это страница поиска статей. Идея использования btree_gin заключается в том, чтобы получить поле 'id' для сортировки и magazine_id в качестве фильтра:

CREATE INDEX idx_gin_search ON article USING gin(id, magazine_id, search_vector_full) WITH (fastupdate = off);

Postgres решает вместо этого использовать индекс btree в журнале, а затем фильтровать (= медленно):

Executed SQL
SELECT ••• FROM article WHERE (( (article.search_vector) @@    
(plainto_tsquery('pg_catalog.english', 'interesting'))) AND    
article.magazine_id = 7) ORDER BY article.id ASC LIMIT 36
Time 13.4780406952 ms

QUERY PLAN
Limit  (cost=2021.87..2021.96 rows=36 width=384) (actual time=9.782..9.787 rows=36 loops=1)
  ->  Sort  (cost=2021.87..2027.49 rows=2248 width=384) (actual time=9.781..9.784 rows=36 loops=1)
    Sort Key: id
    Sort Method: top-N heapsort  Memory: 53kB
    ->  Index Scan using idx_magazine_id on article (cost=0.29..1952.53 rows=2248 width=384) (actual time=0.035..8.924 rows=2249 loops=1)
          Index Cond: (magazine_id = 7)
          Filter: (search_vector @@ '''interesting'''::tsquery)
          Rows Removed by Filter: 11413
Planning time: 4.600 ms
Execution time: 9.860 ms

Затем, что я нахожу даже менее понимающим, так это то, что он также отказывается использовать этот простой индекс btree на странице LIST для статей, где они просто перечислены x на странице в порядке убывания:

CREATE INDEX idx_btree_listing ON article USING btree(id DESC, magazine_id);

Опять же, он не использует индекс с несколькими столбцами:

Executed SQL
SELECT ••• FROM article WHERE article.magazine_id = 7
ORDER BY article.id DESC LIMIT 36
Time 1.4750957489 ms

QUERY PLAN
Limit  (cost=0.29..7.48 rows=36 width=384) (actual time=0.034..0.115 rows=36 loops=1)
->  Index Scan Backward using idx_magazine_id on article  (cost=0.29..2729.56 rows=13662 width=384) (actual time=0.031..0.107 rows=36 loops=1)
    Filter: (magazine_id = 7)
    Planning time: 1.354 ms
    Execution time: 0.207 ms

РЕДАКТИРОВАТЬ: Вышеупомянутая установка разработки с меньшим количеством записей и только 1 магазином, следовательно, высокая скорость. Вот журнал, созданный auto_explain на рабочем сервере:

duration: 230.629 ms  plan:
SELECT article.id, article.title, article.date, article.content FROM article WHERE article.magazine_id = 7 ORDER BY article.id DESC LIMIT 36

Limit  (cost=0.42..43.67 rows=36 width=306) (actual time=229.876..229.995 rows=36 loops=1)
    ->  Index Scan Backward using idx_magazine_id on article (cost=0.42..239539.22 rows=199379 width=306) (actual time=229.866..229.968 rows=36 loops=1)
    Filter: (article.magazine_id = 7)
    Rows Removed by Filter: 116414

Я был бы признателен, если бы кто-нибудь мог дать мне советы по дальнейшей отладке этого.


person tdma    schedule 02.02.2016    source источник
comment
Почему второй оператор должен использовать b-дерево, если результат может быть полностью получен с использованием индекса mmxxx_sitevideo_pkey - при времени выполнения 0,2 миллисекунды мне это кажется достаточно быстрым. Время планирования заняло гораздо больше времени, но общее время выполнения по-прежнему составляет всего 1,5 милли секунды. Какую производительность вы ожидаете? Насколько быстро вам это нужно? Хотя я должен признать, что сроки планирования (особенно первого) кажутся довольно высокими для таких простых утверждений.   -  person a_horse_with_no_name    schedule 02.02.2016
comment
Да, то, что вы говорите, имеет абсолютный смысл, однако я должен уточнить, что они взяты из установки разработки с гораздо меньшим объемом данных, чем рабочий сервер. На рабочем сервере я использовал модуль auto_explain и получил тот же план выполнения. В моей базе данных разработки у меня есть только один magazine_id, на реальном сервере я получаю тот же запрос, а затем это занимает больше времени, извините, я должен был добавить производственный запрос, теперь добавил его в исходное сообщение. (Также забыл переименовать упомянутый вами индекс в idx_magazine_id для упрощения ;-))   -  person tdma    schedule 02.02.2016
comment
Затем опубликуйте план выполнения (используя explain (analyze, verbose) из производства.   -  person a_horse_with_no_name    schedule 02.02.2016
comment
У меня уже есть auto_explain.log_analyze = true и auto_explain.log_verbose = true в начальном посте.   -  person tdma    schedule 02.02.2016
comment
По-видимому, pgsql поддерживает сортировку индексов только в btree (источник: postgresql.org/docs /9.1/static/indexes-ordering.html), поэтому полный индекс моего запроса 1 никогда не будет работать. Поместив поля фильтра в индекс btree и поле полнотекстового поиска отдельно в поле gin, я теперь быстро запускаю его с растровым изображением anding, но ТОЛЬКО без order_by. Pgsql не поддерживает растровое изображение и переход между отсортированным многостолбцовым btree и индексом gin?   -  person tdma    schedule 03.02.2016


Ответы (1)


Первый столбец в вашем индексе с несколькими столбцами - это идентификатор. Вы не фильтруете по идентификатору, поэтому postgres не будет использовать этот индекс. Вам не нужно фильтровать все столбцы в индексе, но столбцы, по которым вы фильтруете, должны быть первыми n столбцами в индексе.

Попробуйте поэкспериментировать с вариантами индекса, которые у вас есть, например, переместите id в конец или исключите id из индекса.

person Eelke    schedule 02.02.2016
comment
Привет, спасибо за ваш отзыв. Я попытался изменить порядок полей индекса, а также без поля id, как вы предлагаете, но план выполнения тот же и остается значительно выше 100 мс... Я думаю, проблема в операции сортировки. Знаете ли вы, будет ли этот запрос (я имею в виду второй в своем первоначальном вопросе) überhaubt поддерживать переход из индекса? - person tdma; 02.02.2016
comment
ХОРОШО. Проблема с запросом 2 РЕШЕНА. Order_by сбивал с толку планировщика. Я перепробовал все, чтобы он работал с запросом как есть, включая изменение default_statistics_target и других параметров планировщика. Он продолжал делать неправильный выбор (снова возникает мысль о том, должны ли postgres иметь индексные подсказки). В конце концов я создал новый столбец с именем id_sort, с идентичным содержимым, что и id, и индексом btree (magazine_id, id_sort desc), который хорошо используется и выполняется за несколько мс. Хотя это довольно абсурдно. - person tdma; 03.02.2016