PostgreSQL은 인덱스에서 null을 사용할 수 있습니까?


10

나는 이 책 을 읽고 있다

데이터베이스는 Indexed_Col IS NOT NULL이 너무 넓은 범위를 포함하여 유용하지 않다고 가정하므로 데이터베이스는이 조건에서 인덱스로 구동되지 않습니다.

나는 그 책이 10 년 이상 된 것을 알고 있지만 이미 매우 유용하다는 것을 알고있다.

또한, 실행에 EXPLAIN ANALYZEA의 SELECT쿼리, 내 인덱스 하나도 경우에도 모든 권리에 의해, 그들은되어야한다, 사용되지되고있는 것으로 나타났습니다.

따라서 내 질문은 다음과 같습니다.

열 정의에 "NOT NULL"이 포함 된 열이 있고이 열을 포함하는 인덱스가 있다고 가정하면이 인덱스는 열이 쿼리의 일부인 해당 테이블의 쿼리에 사용됩니까?

처럼:

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;

답변:


9

PostgreSQL은에 대한 색인을 사용할 있습니다 IS NOT NULL. 해당 조건에 대한 쿼리 플래너 가정도 보이지 않습니다.

열에 대한 null 부분 ( pg_statistic.stanullfrac)이 쿼리에 대해 인덱스가 유용하게 선택 될 수있을 정도로 낮 으면 PostgreSQL은 인덱스를 사용합니다.

나는 당신이 무엇을 말하려고하는지 알 수 없습니다.

이것이 정확하다면, "NOT NULL"로 정의 된 열의 인덱스가 해당 열을 사용하는 쿼리에서 사용되지 않는다는 것을 이해하고 있습니까?

확실히 인덱스는 열의 IS NOT NULL조건에 사용되지 않습니다 NOT NULL. 항상 100 % 행과 일치하므로 seqscan은 거의 항상 훨씬 빠릅니다.

인덱스가 쿼리에 대해 많은 행을 필터링하지 않으면 PostgreSQL은 인덱스를 사용하지 않습니다. 유일한 색인은 색인의 색인과 일치하는 순서로 단일 색인이 포함하는 열 세트를 요청하는 경우입니다. PostgreSQL은 인덱스 전용 스캔을 수행 할 수 있습니다. 예를 들어 색인이 t(a, b, c)있고 당신이 :

select a, b FROM t ORDER BY a, b, c;

행을 필터링하지 않아도 PostgreSQL은 인덱스를 읽을 수 있고 힙 읽기를 건너 뛰고 정렬을 피할 수 있기 때문에 인덱스를 사용할 수 있습니다.


이것은 모두 PG 9.0
eradman

1
또한 Null을 허용하는 열에서도 조건 WHERE column IS NOT NULL이 있는 쿼리 는 인덱스가 사용되지 않을 수 있습니다.이 책은 "너무 큰 범위를 포함하여 유용하지 않습니다"라고 말합니다. 값의 90 %가 널이 아니면 seqscan이 더 빠를 것입니다.
ypercubeᵀᴹ

바로 그거죠. 테이블의 많은 부분이 널인 경우에만 가능합니다. 이 경우 부분 인덱스 가 더 나은 선택 인 경우가 종종 있습니다.
Craig Ringer

예. 나는 (내가 이해하는 바와 같이) "너무 큰 범위를 커버한다"는 부분 은 색인을 나타내지 만 일반적인 조건이 아니라 특정 조건과 관련 이 있다고 말하려고했다 .
ypercubeᵀᴹ

2
@FuriousFolder Heh, 여기에 너무 많은 부정이 있습니다. PostgreSQL은 해당 인덱스가 절의 다른 부분 , 조인 필터 등에 유용하거나 정렬 된 인덱스 전용 스캔에 ​​사용할 수 없는 경우 쿼리 에 대해 NOT NULL열의 인덱스를 사용하지 않습니다 . 즉, 열의 중복 을 완전히 무시하고 다른 세부 정보를 기반으로 인덱스 사용을 선택합니다. 편집, 인덱스 전용 스캔 재 편집을 참조하십시오. IS NOT NULLWHEREIS NOT NULLNOT NULL
Craig Ringer

2

크레이그의 철저한 답변 외에도, 당신이 언급 한 책의 표지가 다음과 같이 덧붙이고 싶었습니다.

Oracle, DB2 및 SQL Server 포함

따라서 PostgreSQL에 대한 훌륭한 조언이 될 것이라고 믿지 않습니다. 모든 RDBMS는 놀라 울 정도로 다를 수 있습니다!

나는 당신의 원래 질문에 대해 약간 혼란 스럽지만 여기 책의 섹션이 100 % 정확하지 않다는 것을 보여주는 예가 있습니다. 더 혼란을 피하기 위해 여기에 관련된 모든 단락이 있습니다 . Google 도서 검색 에서 확인할 수 있습니다 .

데이터베이스는 Indexed_Col IS NOT NULL이 너무 넓은 범위를 포함하여 유용하지 않다고 가정하므로 데이터베이스는이 조건에서 인덱스로 구동되지 않습니다. 드문 경우에, 널이 아닌 값을 갖는 것이 너무 드물기 때문에 모든 가능한 널이 아닌 값에 대한 인덱스 범위 스캔이 유리합니다. 이러한 경우 가능한 모든 값의 범위에 대한 안전한 하한 또는 상한을 알아낼 수 있으면 Positive_ID_Column> -1 또는 Date_Column> TO_DATE ( '0001/01/01'와 같은 조건으로 범위 스캔을 활성화 할 수 있습니다. , 'YYYY / MM / DD').

Postgres는 실제로 (다음과 같은 경우에) IS NOT NULL제안 된 것과 같은 범위 스캔 kludges를 추가하지 않고 쿼리 를 만족시키기 위해 인덱스를 사용할 수 있습니다 Positive_ID_Column > -1. Postgres가이 특정 경우에이 인덱스를 선택한 이유에 대한 Craig의 질문에 대한 의견과 부분 인덱스 사용에 대한 참고 사항을 참조하십시오.

CREATE TABLE bar (a int);
INSERT INTO bar (a) SELECT NULL FROM generate_series(1,1000000);
INSERT INTO bar (a) VALUES (1);
CREATE INDEX bar_idx ON bar (a);

EXPLAIN ANALYZE SELECT * FROM bar WHERE a IS NOT NULL;
                                                QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 Index Only Scan using bar_idx on bar  (cost=0.42..8.44 rows=1 width=4) (actual time=0.094..0.095 rows=1 loops=1)
   Index Cond: (a IS NOT NULL)
   Heap Fetches: 1
 Total runtime: 0.126 ms
(4 rows)

그건 그렇고 Postgres 9.3이지만 "Index Only Scan"을 사용하지 않더라도 결과는 9.1에서 거의 비슷할 것으로 생각합니다.

편집 : 나는 당신이 원래의 질문을 분명히하고 Postgres가 왜 간단한 예제에서 색인을 사용하지 않는지 궁금합니다.

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;

테이블에 행이 없기 때문일 수 있습니다. 테스트 데이터를 추가하십시오 ANALYZE my_table;.


이 책 (강조 광산)에 대한 설명에서 "Dan Tow 저자 는 사용중인 SQL 또는 데이터베이스 플랫폼의 복잡성에 관계없이 최적의 실행 계획을 신속하고 체계적으로 찾기 위해 개발 한 시간 절약 방법을 간략하게 설명합니다. " 아마도 질문의 # 1을 간과했을 것입니다. 즉, 쿼리가 인덱스 조건으로 사용 되는 것이 아니라 열이로 정의 되어 NOT NULL있다는 것 IS NOT NULL입니다. 이것은 귀하가 언급 한 의견에 있지만 질문을 포함하도록 업데이트 할 것입니다.
FuriousFolder

또한,이 책 자체가 언어 무신론자입니다 유일한 DBMS에 특정 부품은 포스트 그레스는 : 아주 간단하게하는, 쿼리 계획을 보여주는에 대해입니다
FuriousFolder

1
@FuriousFolder 열은 NOT NULL로 정의되지만이 부분 (질문에서 책에서) : "Indexed_Col IS NOT NULL covers ..." 은 열 정의가 아닌 where 조건을 나타냅니다. 확실하지는 않지만 상황에 맞지 않기 때문입니다. 아마도 당신은 책의 전체 (앞의) 단락을 포함시켜야합니다.
ypercubeᵀᴹ

-1

검색어 나 예제 데이터를 게시하지 않았습니다. 그러나 인덱스가 사용되지 않는 가장 일반적인 이유는 볼륨과 관련이 있습니다.

인덱스는 열을 행 위치로 변환하는 전화 번호부와 같습니다. 몇 개의 행만 찾으려면 전화 번호부에서 각 행을 찾은 다음 기본 테이블에서 행을 찾으십시오.

그러나 몇 줄 이상인 경우 전화 번호부를 건너 뛰고 기본 테이블의 모든 행을 반복하는 것이 더 저렴합니다. 내 경험상 팁 포인트는 약 100 행입니다.


"색인은 열을 행 위치로 변환하는 전화 번호부와 같습니다. 몇 개의 행만 찾으려면 전화 번호부의 각 행을 찾은 다음 기본 테이블에서 행을 찾는 것이 좋습니다." 실제로 색인은 색인이있는 전화 번호부가 업데이트 될 때마다 업데이트되는 작은 전화 번호부와 같습니다. 작은 전화 번호부를 열 때마다 색인 조건에 설명 된 모든 정보를 찾을 수 있습니다. 예 : 인덱스 테이블에서 이름이 'frank'인 모든 사람 : CREATE INDEX ix_frank ON people(name) WHERE name ='frank'.
FuriousFolder

이를 통해 인덱스 전용 될 스캔 훨씬 많은 당신이 수백만 늘어선 테이블 가능하지 않습니다 메모리에 전체 "작은 전화 번호부"를 읽을 수 있기 때문에, 빨리.
FuriousFolder

@FuriousFolder : 인덱스 전용 스캔을 설명하고 있습니다. 그러나 OP는 인덱스 전용 스캔이 쿼리를 충족시킬 경우 발생하지 않는 인덱스를 사용하지 않는다고 말합니다.
Andomar

Andomar ... 나는 나는 하하, 영업. 나의 목표는 바로 그 것이다. 이 쿼리가 인덱스 전용 스캔을 사용하도록합니다. 크레이그가 postgres 컬럼 정의에 포함 된 컬럼에서 인덱스를 사용할 수 있다고 설명한 이후로이를 달성했습니다.NOT NULL
FuriousFolder
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.