Означает ли SELECT DISTINCT Seq Scan? - PullRequest
0 голосов
/ 05 октября 2018

Я хотел бы знать, подразумевает ли выполнение запроса SELECT DISTINCT последовательное сканирование и как я могу его оптимизировать.

Я создал фиктивную таблицу и подтвердил, что при отсутствии индекса SELECT DISTINCTвыполняет Seq Scan.

test=# create table test2 (id SERIAL, t1 text);
CREATE TABLE
test=# insert into test2 select generate_series(0, 100000) AS id, md5(random()::text) AS t1;
INSERT 0 100001
test=# explain analyze select distinct t1 from test2;

Результаты:

                                                     QUERY PLAN
--------------------------------------------------------------------------------------------------------------------
 HashAggregate  (cost=2157.97..2159.97 rows=200 width=32) (actual time=54.086..77.352 rows=100000 loops=1)
   Group Key: t1
   ->  Seq Scan on test2  (cost=0.00..1893.18 rows=105918 width=32) (actual time=0.012..12.232 rows=100001 loops=1)
 Planning time: 0.079 ms
 Execution time: 86.345 ms
(5 rows)

При создании индекса:

test=# create index test2_idx_t1 on test2 (t1);
CREATE INDEX
test=# explain analyze select distinct t1 from test2;

Результаты:

сначалавремя:

                                                    QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
 HashAggregate  (cost=2084.01..2086.01 rows=200 width=32) (actual time=48.871..74.617 rows=100000 loops=1)
   Group Key: t1
   ->  Seq Scan on test2  (cost=0.00..1834.01 rows=100001 width=32) (actual time=0.009..9.891 rows=100001 loops=1)
 Planning time: 0.145 ms
 Execution time: 83.564 ms
(5 rows)

второй раз и далее:

QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------
 Unique  (cost=0.42..7982.42 rows=100001 width=33) (actual time=0.016..80.949 rows=100000 loops=1)
   ->  Index Only Scan using test2_idx_t1 on test2  (cost=0.42..7732.42 rows=100001 width=33) (actual time=0.015..53.396 rows=100001 loops=1)
         Heap Fetches: 100001
 Planning time: 0.053 ms
 Execution time: 87.552 ms
(5 rows)
  1. Почему выполняется Seq Scan при первом запросе после создания индекса?
  2. Почему сканирование индекса в этом случае обходится дороже, чем сканирование seq, и почему его выбирает планировщик запросов?

1 Ответ

0 голосов
/ 05 октября 2018

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

Единственный способ избежать последовательного сканирования таблицы - это включить индекс наt1 и иметь недавно очищенную таблицу, так что большинство блоков «все видимы».Затем можно использовать «сканирование только по индексу», которое обычно дешевле.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...