Как я могу заставить PostgreSQL использовать определенный индекс? - PullRequest
0 голосов
/ 13 июня 2019

У меня в таблице два индекса Postgres cache, оба в столбце jsonb в полях date и condition.

Первый работает с неизменяемой функцией, которая принимает текстполе и преобразует его в тип date.

Второй создается только на text.

Итак, когда я попробовал второй, он превращает мой индекс btree виндекс растрового изображения и как-то работает медленнее, чем первый, который требует еще двух шагов, но использует только сканирование индекса.

У меня два вопроса: почему и как?

Почемупервый использует только индекс, по сравнению со вторым, который по какой-то причине использует растровое изображение?И как я могу заставить PostgreSQL использовать только индекс, а не растровое изображение для второго индекса, потому что я не хочу использовать функцию.

Если есть другое решение, пожалуйста, дайте мне подсказки, потому что я неУ него нет разрешения на установку пакетов на сервере.

Индекс функции:

create index cache_ymd_index on cache (
   to_yyyymmdd_date(((data -> 'Info'::text) ->> 'Date'::text)::character varying),
   ((data -> 'Info'::text) ->> 'Condition'::text)
)  where (((data -> 'Info'::text) ->> 'Condition'::text) = '3'::text);

Текстовый индекс:

create index cache_data_index on cache (
   ((data -> 'Info'::text) ->> 'Date'::text),
   ((data -> 'Info'::text) ->> 'Condition'::text)
) where (((data -> 'Info'::text) ->> 'Condition'::text) = '3'::text);

Сама функция:

create or replace function to_yyyymmdd_date(the_date character varying) returns date
    immutable language sql
as
$$
select to_date(the_date, 'YYYY-MM-DD')
$$;

Условие АНАЛИЗ для индекса функции:

Index Scan using cache_ymd_index on cache  (cost=0.29..1422.43 rows=364 width=585) (actual time=0.065..66.842 rows=71634 loops=1)
  Index Cond: ((to_yyyymmdd_date((((data -> 'Info'::text) ->> 'Date'::text))::character varying) >= '2018-01-01'::date) AND (to_yyyymmdd_date((((data -> 'Info'::text) ->> 'Date'::text))::character varying) <= '2020-12-01'::date))
Planning Time: 0.917 ms
Execution Time: 70.464 ms

Условие АНАЛИЗ для индекса текста:

Bitmap Heap Scan on cache  (cost=12.15..1387.51 rows=364 width=585)    (actual time=53.794..87.802 rows=71634 loops=1)
  Recheck Cond: ((((data -> 'Info'::text) ->> 'Date'::text) >= '2018-01-01'::text) AND (((data -> 'Info'::text) ->> 'Date'::text) <= '2020-12-01'::text) AND (((data -> 'Info'::text) ->> 'Condition'::text) = '3'::text))
  Heap Blocks: exact=16465
  ->  Bitmap Index Scan on cache_data_index  (cost=0.00..12.06 rows=364 width=0) (actual time=51.216..51.216 rows=71634 loops=1)
        Index Cond: ((((data -> 'Info'::text) ->> 'Date'::text) >= '2018-01-01'::text) AND (((data -> 'Info'::text) ->> 'Date'::text) <= '2020-12-01'::text))
Planning Time: 0.247 ms
Execution Time: 90.586 ms

1 Ответ

1 голос
/ 13 июня 2019

«Сканирование индекса растрового изображения» также является сканированием индекса.Это именно то, что PostgreSQL обычно выбирает, если нужно посетить больший процент блоков таблицы, потому что в этом случае он более эффективен.

Для сканирования диапазона индекса, как в вашем случае, есть два возможных объясненияthis:

  1. ANALYZE выполнено между двумя индексами, которые были созданы, так что PostgreSQL знает о распределении индексированных значений в одном случае, но не в другом.

    Чтобы выяснить, так ли это, запустите

    ANALYZE cache;
    

    , а затем снова попробуйте два оператора.Возможно, сейчас планы более похожи.

  2. Операторы выполнялись в двух разных таблицах, которые содержат одинаковые данные, но физически они расположены по-разному, так что корреляция хороша с одной стороны, но плоха с другой.Если корреляция близка к 1 или -1, сканирование индекса становится дешевле.В противном случае лучшим вариантом будет сканирование растрового индекса.

    Поскольку вы указываете, что в обоих случаях это одна и та же таблица, это объяснение можно исключить.

второй столбец вашего индекса лишний;Вы должны просто опустить это.В противном случае ваши два индекса должны работать примерно одинаково.

Конечно, все это будет работать намного лучше, если таблица будет определена с помощью столбца date на первом месте ...

...