PostgreSQL이 인덱스 열에서 순차적 스캔을 수행하는 이유는 무엇입니까?


150

매우 간단한 예-하나의 테이블, 하나의 인덱스, 하나의 쿼리 :

CREATE TABLE book
(
  id bigserial NOT NULL,
  "year" integer,
  -- other columns...
);

CREATE INDEX book_year_idx ON book (year)

EXPLAIN
 SELECT *
   FROM book b
  WHERE b.year > 2009

나에게 준다 :

Seq Scan on book b  (cost=0.00..25663.80 rows=105425 width=622)
  Filter: (year > 2009)

대신 인덱스 스캔을 수행하지 않는 이유는 무엇입니까? 내가 무엇을 놓치고 있습니까?

답변:


222

SELECT가 테이블에있는 모든 행의 약 5-10 % 이상을 리턴하면 순차 스캔이 인덱스 스캔보다 훨씬 빠릅니다.

인덱스 스캔에는 각 행에 대해 여러 개의 IO 조작이 필요하기 때문입니다 (인덱스 에서 행을 찾은 다음 힙에서 행을 검색하십시오). 순차 스캔에는 각 행마다 단일 IO 만 필요하지만 디스크의 블록 (페이지)에 둘 이상의 행이 포함되어 있으므로 단일 IO 조작으로 둘 이상의 행을 페치 할 수 있습니다.

Btw : 이것은 다른 DBMS에서도 마찬가지입니다. "인덱스 만 스캔"과 같은 일부 최적화 (하지만 SELECT의 경우 * DBMS가 "인덱스 만 스캔"으로 갈 가능성은 거의 없습니다)


12
5-10 %는 몇 가지 구성 설정과 데이터 저장에 따라 다릅니다. 어려운 숫자가 아닙니다.
Frank Heikens

6
@Frank : 그게 지적에 대해 나는 "약"라고 이유 :하지만 덕분에
a_horse_with_no_name

5
또한 순차 스캔은 한 번에 힙에서 여러 페이지를 요청할 수 있으며 커널에서 현재 청크에서 작동하는 동안 다음 청크를 페치하도록 요청할 수 있습니다. 인덱스 스캔은 한 번에 한 페이지를 페치합니다. (비트 맵 스캔은 둘 사이에서 절충을합니다. 일반적으로 인덱스 스캔에 대해서는 선택적이지 않지만 여전히 전체 테이블 스캔을 수행 할만큼 선택적이지 않은 쿼리에 대한 계획에 나타납니다)
araqnid

4
흥미로운 질문은 데이터베이스가 쿼리를 먼저 수행하지 않고 반환 할 행 수를 어떻게 알 수 있는가입니다. 다른 값의 수 대 테이블 크기와 같은 통계를 저장합니까?
Laurent Grégoire

7
@ LaurentGrégoire : 예, 데이터베이스는 행 수와 값 분포에 대한 통계를 저장합니다. 자세한 내용은 매뉴얼을 참조하십시오 : postgresql.org/docs/current/static/planner-stats.html
a_horse_with_no_name

13

테이블 / 데이터베이스 를 분석 했습니까 ? 그리고 통계는 어떻습니까? 2009 년보다 많은 레코드가있는 경우 순차적 스캔이 인덱스 스캔보다 빠를 수 있습니다.


0

인덱스 스캔에서 읽기 헤드는 한 행에서 다른 행으로 점프하여 다음 물리적 블록을 읽는 것보다 1000 배 느립니다 (순차 스캔에서).

따라서 (검색 할 레코드 수 * 1000)이 총 레코드 수보다 적 으면 인덱스 스캔이 더 잘 수행됩니다.


0

@a_horse_with_no_name은 꽤 잘 설명했습니다. 또한 실제로 인덱스 스캔을 사용하려면 where 절에서 경계 범위를 사용해야합니다. 예 :-2019 년 및 2020 년

통계가 테이블에서 업데이트되지 않는 경우가 많으며 제약 조건으로 인해 통계를 업데이트하지 못할 수도 있습니다. 이 경우 옵티마이 저는 2019 년에 얼마나 많은 행을 가져야하는지 알 수 없으므로 전체 지식 대신 ​​순차적 스캔을 선택합니다. 경계 파티션은 대부분 문제를 해결합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.