NULL 값으로 부울에 대해 쿼리를 수행 할 때 예기치 않은 Seq 스캔


10

auto_reviewcolumn type is 라는 데이터베이스 열 이 boolean있습니다. ActiveRecord ORM을 사용하여 작성된 해당 필드에 대한 색인이 있습니다.

CREATE INDEX index_table_on_auto_renew ON table USING btree (auto_renew);

부울 값을 필드에 쿼리하면 PG가 예상대로 색인을 사용합니다.

EXPLAIN for: SELECT "table".* FROM "table"  WHERE "table"."auto_renew" = 'f'
                                          QUERY PLAN
----------------------------------------------------------------------------------------------
 Bitmap Heap Scan on table  (cost=51.65..826.50 rows=28039 width=186)
   Filter: (NOT auto_renew)
   ->  Bitmap Index Scan on index_domains_on_auto_renew  (cost=0.00..44.64 rows=2185 width=0)
         Index Cond: (auto_renew = false)
(4 rows)

값 인 경우 NULL, 순차 주사가 사용된다.

EXPLAIN for: SELECT "table".* FROM "table"  WHERE "table"."auto_renew" IS NULL
                           QUERY PLAN
----------------------------------------------------------------
 Seq Scan on table  (cost=0.00..1094.01 rows=25854 width=186)
   Filter: (auto_renew IS NULL)
(2 rows)

이 선택의 이유를 알고 싶습니다.

답변:


19

일반적으로 col IS NULL(기본) b- 트리 인덱스 검색의 후보입니다. 매뉴얼 :

또한 인덱스 열의 IS NULLor IS NOT NULL조건을 B- 트리 인덱스와 함께 사용할 수 있습니다.

증거를 얻으려면 순차 스캔을 비활성화하십시오 (테스트 세션에서만!) :

SET enable_seqscan = OFF;

나는 여기에 매뉴얼을 인용 한다 :

enable_seqscan (boolean)

쿼리 플래너의 순차 스캔 계획 유형 사용을 사용하거나 사용하지 않습니다. 순차 스캔을 완전히 억제하는 것은 불가능하지만,이 변수를 끄면 다른 방법이있는 경우 플래너가 하나를 사용하지 못하게됩니다. 기본 설정은 켜져 있습니다.

그런 다음 다시 시도하십시오.

EXPLAIN ANALYZE SELECT * FROM tbl WHERE auto_renew IS NULL;

이로 인해 비트 맵 인덱스 스캔이 테이블의 순차 스캔보다 느릴 수 있습니다.

세션을 재설정하거나 닫습니다 (설정은 session-local).

RESET enable_seqscan;

boolean열의 인덱스 는 특정 경우에만 유용합니다. 플래너는 인덱스가 더 빠를 것으로 예상되는 경우에만 인덱스를 사용합니다. 계산은 비용 설정 및에 의해 수집 된 통계를 기반으로합니다 ANALYZE. 테이블의 상당 부분이 조건 (약 5 % 이상에 따라 다름)과 일치하면 일반적으로 전체 테이블 스캔을 수행하는 것이 더 빠릅니다.

이렇게 하면 열의 희귀boolean이 일반 인덱스의 유일한 유용한 후보로 남습니다 . 또한 일반적으로이를 위해 (보다 전문화 된) 부분 인덱스 를 만드는 것이 더 효율적 입니다. 쿼리 조건이 일치하는 경우 유지 관리가 저렴하고, 작고, 빠르며, 더 쉽게 사용됩니다.

당신이 가진 행을 찾고 쿼리가 많이있는 경우 auto_renew IS NULLNULL다음이 지수가 빠르게 / 종류의 이러한 행을 찾기 위해 도움이 될 경우는 매우 흔한되지 않습니다 (및 / 또는 특정 정렬 순서를 필요) :

CREATE INDEX index_tbl_tbl_id_auto_renew_null ON tbl (tbl_id)
WHERE auto_renew IS NULL;

WHERE쿼리 플래너가 인덱스가 적용 가능하다는 것을 깨닫게하려면 쿼리 의 절 에서 부분 인덱스의 조건을 반복해야합니다 .

색인화 된 열 ( tbl_id)은 임의 선택입니다. 중요한 부분은 WHERE절입니다. 이 특정 인덱스는 ORDER BY tbl_id필터를 추가하거나 조인하는 쿼리에 가장 효과적입니다 tbl_id. 다중 열 인덱스로 만들 수 있습니다 . 부울 열은 종종 다른 열과 함께 사용하는 것이 더 유용합니다.

따로 : ORM은 정기적으로 RDBMS에서 최대한의 잠재력을 발휘하지 못하는 목발입니다.


훌륭한 답변, Erwin에게 감사합니다. 나는 그것을 두 번지지 할 수 없어서 슬프다.
Simone Carletti
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.