[SQL] PostgreSQL은 부분 인덱스를 사용하지 않습니다
SQLPostgreSQL은 부분 인덱스를 사용하지 않습니다
나는 텍스트 열이 PostgreSQL의 9.2의 테이블이있다. 의이 text_col를 부르 자. 이 열의 값 (기껏해야 5-6 중복을 포함 할 수있다) 매우 독특하다. 표는 ~ 500 만 개 행이 있습니다. 절반을 다음 행은 text_col에 대한 널 (null) 값이 포함되어 있습니다. 나는 다음과 같은 쿼리를 실행할 때 나는 1-5 행을 기대합니다. 대부분의 경우 (> 80 %) 난 단지 1 개 행을 기대합니다.
explain analyze SELECT col1,col2.. colN
FROM table
WHERE text_col = 'my_value';
BTREE 지수는 text_col에 존재합니다. 이 인덱스는 쿼리 계획에 의해 사용되지 않습니다와 나는 확실히 왜 안입니다. 이 쿼리의 출력입니다.
Seq Scan on two (cost=0.000..459573.080 rows=93 width=339) (actual time=1392.864..3196.283 rows=2 loops=1)
Filter: (victor = 'foxtrot'::text)
Rows Removed by Filter: 4077384
(또는 text_pattern_ops없이. 내 쿼리로 표현에는 LIKE 조건을 고려하지 text_pattern_ops 필요하지 않습니다,하지만 그들은 또한 평등과 일치) 내가 널되지 않은 그 값을 필터링합니다 다른 부분 인덱스를 추가,하지만 도움이되지 않았다.
CREATE INDEX name_idx
ON table
USING btree
(text_col COLLATE pg_catalog."default" text_pattern_ops)
WHERE text_col IS NOT NULL;
세트 enable_seqscan = 오프 시퀀스를 사용하여 검사를 중지; 플래너는 여전히 index_scan 통해 seqscan을 선택합니다. 요약해서 말하자면...
해결법
-
==============================
1.부분 인덱스는 분명히 필요하지 않은 테이블의 절반 행을 제외하는 좋은 아이디어이다. 간단한 :
부분 인덱스는 분명히 필요하지 않은 테이블의 절반 행을 제외하는 좋은 아이디어이다. 간단한 :
CREATE INDEX name_idx ON table (text_col) WHERE text_col IS NOT NULL;
인덱스를 생성 한 후 테이블을 분석 실행해야합니다. (자동 진공 자동으로 수동으로하지 않지만, 당신이 바로 생성 후 테스트하는 경우, 테스트가 실패하면 잠시 후 그 않습니다.)
그런 다음, 특정 부분 인덱스를 사용할 수있는 쿼리 플래너를 설득, 반복 조건이 쿼리에서 어디 - 완전히 중복 보인다하더라도 :
SELECT col1,col2, .. colN FROM table WHERE text_col = 'my_value' AND text_col IS NOT NULL; -- repeat condition
짜잔.
문서 별 :
매개 변수가있는 쿼리에 관해서는 : 다시, WHERE 조건을 추가, 상수로 부분 인덱스의 (중복) 술어를 추가하고 그것을 잘 작동합니다.
포스트 그레스 9.6에서 중요한 업데이트는 크게 (쿼리를 저렴하게 할 수 있으며 쿼리 계획이 더 쉽게 같은 쿼리 계획을 선택합니다) 인덱스 만 스캔을위한 기회를 향상시킵니다. 관련 :
-
==============================
2.조건이 일치 WHERE 경우 부분 인덱스에만 사용됩니다. 따라서 text_col 당신이 당신의 선택에 동일한 조건을 사용하는 경우에만 사용할 수 있습니다 NULL NOT IS WHERE와 인덱스. 정렬 불일치는 해를 입힐 수 있습니다.
조건이 일치 WHERE 경우 부분 인덱스에만 사용됩니다. 따라서 text_col 당신이 당신의 선택에 동일한 조건을 사용하는 경우에만 사용할 수 있습니다 NULL NOT IS WHERE와 인덱스. 정렬 불일치는 해를 입힐 수 있습니다.
다음을 시도해보십시오
-
==============================
3.나는 그것을 알아. 빌드를하는 데 도움이 분석 pg_stats보기에 면밀한 관찰을 복용하면, 나는 문서에서 발췌을 가로 질러왔다.
나는 그것을 알아. 빌드를하는 데 도움이 분석 pg_stats보기에 면밀한 관찰을 복용하면, 나는 문서에서 발췌을 가로 질러왔다.
내 로컬 상자에서 상관 관계 수는 0.97이며, 생산에 0.05이었다. 따라서 플래너는 모든 행을 이동 순차적으로 대신 디스크 블록의 랜덤 액세스에 인덱스 매번 다이빙을 찾는 것이 쉽다는 것을 추정된다. 이 상관 관계 번호로 들여다하는 데 사용되는 쿼리 I입니다.
select * from pg_stats where tablename = 'table_name' and attname = 'text_col';
이 테이블은 또한 행에서 수행 몇 가지 업데이트가 있습니다. 행의 avg_width 20 바이트로 추정된다. 업데이트 텍스트 컬럼에 대한 큰 값을 가지는 경우에는 평균값을 초과하고 또한 느린 업데이트 될 수있다. 내 생각은 물리적 및 논리적 순서는 각 업데이트와 떨어져 이동 둔화되는 것이 었습니다. 나는 다음과 같은 쿼리를 실행 한 수정합니다.
ALTER TABLE table_name SET (FILLFACTOR = 80); VACUUM FULL table_name; REINDEX TABLE table_name; ANALYZE table_name;
아이디어는 내가 잃어버린 공간을 확보하고 물리적 및 논리적 질서를 유지하기 위해 20 %의 버퍼와 진공 각 디스크 블록을 전체 테이블을 줄 수 있다는 것입니다. 내가 이런 짓을 한 후 쿼리는 인덱스를 선택합니다.
explain analyze SELECT col1,col2... colN FROM table_name WHERE text_col is not null AND text_col = 'my_value';
Index Scan using tango on two (cost=0.000..165.290 rows=40 width=339) (actual time=0.083..0.086 rows=1 loops=1) Index Cond: ((victor five NOT NULL) AND (victor = 'delta'::text))
널 (NULL) 조건을 제외하면 비트 맵 힙 검사와 다른 인덱스를 선택합니다.
Bitmap Heap Scan on two (cost=5.380..392.150 rows=98 width=339) (actual time=0.038..0.039 rows=1 loops=1) Recheck Cond: (victor = 'delta'::text) -> Bitmap Index Scan on tango (cost=0.000..5.360 rows=98 width=0) (actual time=0.029..0.029 rows=1 loops=1) Index Cond: (victor = 'delta'::text)
그것은 처음에 상관처럼 보였다 동안 자신의 데이터베이스에 0에 가까운 상관 값은 여전히 인덱스 스캔으로 이어진 @ 마이크 스캔 인덱스 선택에 중요한 역할을 관찰했다한다. 완전히 채우기 비율을 변경하고 진공 청소기로 청소하는 것은 도움이하지만 난 이유를 확실 해요했다.
from https://stackoverflow.com/questions/26030354/postgresql-does-not-use-a-partial-index by cc-by-sa and MIT license
'SQL' 카테고리의 다른 글
[SQL] 테이블에 계층 적 데이터의 모든 자식 노드를 계산 (0) | 2020.07.11 |
---|---|
[SQL] 엔티티 프레임 워크 데이터베이스 먼저 대다 (0) | 2020.07.11 |
[SQL] XAMPP에 연결 SQLSRV (0) | 2020.07.11 |
[SQL] ORDER BY 별칭이 작동하지 않습니다 (0) | 2020.07.11 |
[SQL] 쿼리를 작성하는 문자열 연결을 피 (0) | 2020.07.11 |