Почему мой SQL-запрос Postgres не использует индекс

У меня есть таблица (sales_points) с ~ 23 миллионами строк. Он имеет индекс B-дерева (store_id, book_id). Я ожидаю, что следующий запрос будет использовать этот индекс, но EXPLAIN указывает, что он выполняет последовательное сканирование:

select distinct store_id, book_id from sales_points

Вот вывод EXPLAIN:

Unique  (cost=2050448.88..2086120.31 rows=861604 width=8)
  ->  Sort  (cost=2050448.88..2062339.35 rows=23780957 width=8)
        Sort Key: store_id, book_id
        ->  Seq Scan on sales_points  (cost=0.00..1003261.87 rows=23780957 width=8)

Если я это сделаю, он использует индекс:

select distinct book_id from sales_points where store_id = 1

Вот вывод EXPLAIN этого запроса:

HashAggregate  (cost=999671.02..999672.78 rows=587 width=4)
  ->  Bitmap Heap Scan on sales_points  (cost=55576.17..998149.04 rows=3043963 width=4)
        Recheck Cond: (store_id = 1)
        ->  Bitmap Index Scan on index_sales_points_on_store_id_and_book_id  (cost=0.00..55423.97 rows=3043963 width=0)
              Index Cond: (store_id = 1)

Вот таблица DDL:

CREATE TABLE sales_points
(
  id serial NOT NULL,
  book_id integer,
  store_id integer,
  date date,
  created_at timestamp without time zone,
  updated_at timestamp without time zone,
  avg_list_price numeric(5,2),
  royalty_amt numeric(9,2),
  currency character varying(255),
  settlement_date date,
  paid_sales integer,
  paid_returns integer,
  free_sales integer,
  free_returns integer,
  lent_units integer,
  lending_revenue numeric(9,2),
  is_placeholder boolean,
  distributor_id integer,
  source1_id integer,
  source2_id integer,
  source3_id integer,
  CONSTRAINT sales_points_pkey PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);

Вот индексное выражение:

CREATE INDEX index_sales_points_on_store_id_and_book_id
  ON sales_points
  USING btree
  (store_id, book_id);

Так почему бы Postgres не использовать индекс для ускорения SELECT?


person Jack R-G    schedule 03.05.2014    source источник
comment
Каково определение таблицы? Можете ли вы опубликовать DDL?   -  person a_horse_with_no_name    schedule 04.05.2014


Ответы (1)


Что ж, я думаю, что ваш индекс работает нормально, когда это необходимо. В вашем первом запросе нет предложения WHERE, поэтому Postgres все равно придется извлекать все записи в таблице.

Просто для тестирования вы можете принудительно использовать индекс, отключив последовательное сканирование:

SET enable_seqscan = OFF;

Postgres выбирает свой план сканирования в зависимости от различных условий. Взято с: http://www.postgresql.org/docs/9.2/static/indexes-examine.html

... Когда индексы не используются, для тестирования может быть полезно принудительно их использовать. Существуют параметры времени выполнения, которые могут отключать различные типы планов. Например, отключение последовательного сканирования (enable_seqscan) и соединений с вложенным циклом (enable_nestloop), которые являются самыми базовыми планами, заставит систему использовать другой план. Если система по-прежнему выбирает последовательное сканирование или соединение с вложенным циклом, то, вероятно, существует более фундаментальная причина, по которой индекс не используется...

person Federico Cristina    schedule 03.05.2014
comment
Первый запрос может быть возвращен только при просмотре индекса, а в версии 9.2 есть сканирование только индекса. Так что вопрос в чем-то актуален. - person a_horse_with_no_name; 04.05.2014
comment
@a_horse_with_no_name Я не говорил, что это неправильный вопрос ;) - person Federico Cristina; 04.05.2014
comment
Я имел в виду ваше утверждение Postgres должен будет получить все записи в таблице - это также может быть индексом. - person a_horse_with_no_name; 04.05.2014