Почему postgres сканирует всю таблицу? - PullRequest
0 голосов
/ 30 июня 2018

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

mydatabase=> explain analyze SELECT account_id,num_tokens,tok_holdings FROM tokacct WHERE address='00000000000000000';
                                            QUERY PLAN                                            
--------------------------------------------------------------------------------------------------
 Seq Scan on tokacct  (cost=0.00..6.69 rows=1 width=27) (actual time=0.046..0.046 rows=0 loops=1)
   Filter: (address = '00000000000000000'::text)
   Rows Removed by Filter: 225
 Planning time: 0.108 ms
 Execution time: 0.075 ms
(5 rows)

mydatabase=> 

Однако \di показывает, что у меня есть уникальный индекс:

mydatabase=> \di
                         List of relations
 Schema |          Name           | Type  | Owner  |     Table      
--------+-------------------------+-------+--------+----------------
......
 public | tokacct_address_key     | index | mydb   | tokacct
.....

Моя таблица определена так:

CREATE TABLE tokacct (
        tx_id                           BIGINT                  NOT NULL,
        account_id                      SERIAL                  PRIMARY KEY,
        state_acct_id                   INT                     NOT NULL DEFAULT 0,        
        num_tokens                      INT                     DEFAULT 0,
        ts_created                      INT                     DEFAULT 0,
        block_created           INT                             DEFAULT 0,
        address                         TEXT                    NOT NULL UNIQUE
        tok_holdings                    TEXT                    DEFAULT ''                      
);

Как видите, поле address объявлено как UNIQUE. \di также подтверждает наличие индекса. Итак, почему он использует последовательное сканирование на столе?

Seq Scan on tokacct  (cost=0.00..6.69 rows=1 width=27) (actual time=0.046..0.046 rows=0 loops=1)

1 Ответ

0 голосов
/ 30 июня 2018

создать одну таблицу страниц:

db=# create table small as select g, chr(g) from generate_series(1,200) g;
SELECT 200
db=# create index small_i on small(g);
CREATE INDEX
db=# analyze small;
ANALYZE

послед. Сканирование:

db=# explain (analyze, verbose, buffers) select g from small where g = 200;
                                              QUERY PLAN
------------------------------------------------------------------------------------------------------
 Seq Scan on public.small  (cost=0.00..3.50 rows=1 width=4) (actual time=0.044..0.045 rows=1 loops=1)
   Output: g
   Filter: (small.g = 200)
   Rows Removed by Filter: 199
   Buffers: shared hit=1
 Planning time: 1.360 ms
 Execution time: 0.066 ms
(7 rows)

создать таблицу из трех страниц:

db=# drop table small;
DROP TABLE
db=# create table small as select g, chr(g) from generate_series(1,500) g;
SELECT 500
db=# create index small_i on small(g);
CREATE INDEX
db=# analyze small;
ANALYZE
db=# explain (analyze, verbose, buffers) select g from small where g = 200;
                                                        QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------
 Index Only Scan using small_i on public.small  (cost=0.27..8.29 rows=1 width=4) (actual time=3.194..3.195 rows=1 loops=1)
   Output: g
   Index Cond: (small.g = 200)
   Heap Fetches: 1
   Buffers: shared hit=1 read=2
 Planning time: 0.271 ms
 Execution time: 3.747 ms
(7 rows)

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

как узнать количество страниц? так говорится в (подробном) плане выполнения. А стол?

db=# select max(ctid) from small;
  max
--------
 (2,48)
(1 row)

Здесь 2, означает вторую страницу (отсчитывается от нуля).

или снова из подробного плана:

db=# set enable_indexonlyscan to off;
SET
db=# set enable_indexscan to off;
SET    
db=# set enable_bitmapscan to off;
SET
db=# explain (analyze, verbose, buffers) select g from small where g = 200;
                                              QUERY PLAN
------------------------------------------------------------------------------------------------------
 Seq Scan on public.small  (cost=0.00..9.25 rows=1 width=4) (actual time=0.124..0.303 rows=1 loops=1)
   Output: g
   Filter: (small.g = 200)
   Rows Removed by Filter: 499
   Buffers: shared hit=3
 Planning time: 0.105 ms
 Execution time: 0.327 ms
(7 rows)

Здесь хит = 3

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