BTree
여기서 내 문제는 BTree 인덱스가 중복 값을 저장하기 때문에 실패하기 때문에 커질 것입니다 (테이블이 실제로 정렬되어 있다고 가정 할 수 없으므로 너무 큽니다). BTree가 크면 인덱스와 인덱스가 가리키는 테이블의 부분을 모두 읽어야합니다 ...
반드시 그럴 필요는 없다- '덮고있는' btree 인덱스를 갖는 것이 가장 빠른 읽기 시간이 될 것이며, 그것이 원하는 모든 것이라면 (즉, 추가 스토리지를 감당할 수있는 경우) 가장 좋은 방법입니다.
브린
내 이해는 쓸모없는 페이지를 읽는 대신에 작은 인덱스를 가질 수 있다는 것입니다. 작은 값을 사용 pages_per_range
한다는 것은 색인이 더 크다는 것을 의미하며 (전체 색인을 읽어야하기 때문에 BRIN에 문제가 있음) 큰 pages_per_range
의미가 있으면 쓸모없는 페이지를 많이 읽게됩니다.
당신이 커버 BTREE 인덱스의 저장 오버 헤드를 감당할 수없는 경우, BRIN 당신이 이미 클러스터링 때문에 (이, 당신을 위해 이상적입니다 중요하다 BRIN 유용 할 때까지). BRIN 색인 은 크기가 작 으므로 적절한 값을 선택하면 모든 페이지가 메모리에있을 수 있습니다 pages_per_range
.
이러한 장단점을 고려하여 pages_per_range의 좋은 가치를 찾는 마술 공식이 있습니까?
마술 공식은 없지만 평균 값이 차지하는 평균 크기 (페이지 단위) pages_per_range
보다 약간 작은 것으로 시작 a
합니다. 일반적인 쿼리에 대해 (검색된 BRIN 페이지 수) + (검색된 힙 페이지 수)를 최소화하려고합니다. 를 찾을 Heap Blocks: lossy=n
에 대한 실행 계획 pages_per_range=1
과에 대한 다른 값과 비교 pages_per_range
- 즉, 스캔 얼마나 많은 불필요한 힙 블록을 참조하십시오.
진 / 소녀
그것들은 주로 전체 텍스트 검색에 사용되기 때문에 여기에 관련이 있는지 확실하지 않지만 중복 키를 다루는 데 능숙하다고 들었습니다. 겠습니까 중 하나 GIN
/ GiST
여기에 인덱스 도움?
GIN은 고려할 가치가 있지만 아마도 GiST는 아닐 것입니다. 그러나 자연 군집이 실제로 좋으면 BRIN이 더 나은 방법 일 것입니다.
다음은 더미 데이터에 대한 서로 다른 인덱스 유형 간의 샘플 비교입니다.
테이블 및 인덱스 :
create table foo(a,b,c) as
select *, lpad('',20)
from (select chr(g) a from generate_series(97,122) g) a
cross join (select generate_series(1,100000) b) b
order by a;
create index foo_btree_covering on foo(a,b);
create index foo_btree on foo(a);
create index foo_gin on foo using gin(a);
create index foo_brin_2 on foo using brin(a) with (pages_per_range=2);
create index foo_brin_4 on foo using brin(a) with (pages_per_range=4);
vacuum analyze;
관계 크기 :
select relname "name", pg_size_pretty(siz) "size", siz/8192 pages, (select count(*) from foo)*8192/siz "rows/page"
from( select relname, pg_relation_size(C.oid) siz
from pg_class c join pg_namespace n on n.oid = c.relnamespace
where nspname = current_schema ) z;
이름 | 크기 | 페이지 | 행 / 페이지
: ----------------- | : ------ | ---- : | -------- :
foo | 149 MB | 19118 | 135
foo_btree_covering | 56MB | 7132 | 364
foo_btree | 56MB | 7132 | 364
foo_gin | 2928 킬로바이트 | 366 | 7103
foo_brin_2 | 264 킬로바이트 | 33 | 78787
foo_brin_4 | 136 킬로바이트 | 17 | 152941
취재 btree :
explain analyze select sum(b) from foo where a='a';
| 쿼리 계획 |
| : ------------------------------------------------- -------------------------------------------------- ------------------------------------------- |
| 집계 (비용 = 3282.57..3282.58 행 = 1 너비 = 8) (실제 시간 = 45.942..45.942 행 = 1 루프 = 1) |
| -> 인덱스 전용 foo에서 foo_btree_covering을 사용하여 스캔 (비용 = 0.43..3017.80 rows = 105907 너비 = 4) (실제 시간 = 0.038..27.286 rows = 100000 루프 = 1) |
| 인덱스 조건 : (a = 'a':: text) |
| 힙 페치 : 0 |
| 계획 시간 : 0.099 ms |
| 실행 시간 : 45.968 ms |
평범한 나무 :
drop index foo_btree_covering;
explain analyze select sum(b) from foo where a='a';
| 쿼리 계획 |
| : ------------------------------------------------- -------------------------------------------------- ----------------------------- |
| 집계 (비용 = 4064.57..4064.58 rows = 1 width = 8) (실제 시간 = 54.242..54.242 rows = 1 루프 = 1) |
| -> foo에서 foo_btree를 사용한 인덱스 스캔 (비용 = 0.43..3799.80 rows = 105907 너비 = 4) (실제 시간 = 0.037..33.084 rows = 100000 루프 = 1) |
| 인덱스 조건 : (a = 'a':: text) |
| 계획 시간 : 0.135 ms |
| 실행 시간 : 54.280 ms |
BRIN pages_per_range = 4 :
drop index foo_btree;
explain analyze select sum(b) from foo where a='a';
| 쿼리 계획 |
| : ------------------------------------------------- -------------------------------------------------- ----------------------------- |
| 집계 (비용 = 21595.38..21595.39 rows = 1 너비 = 8) (실제 시간 = 52.455..52.455 rows = 1 루프 = 1) |
| -> foo에서 비트 맵 힙 스캔 (cost = 888.78..21330.61 rows = 105907 width = 4) (실제 시간 = 2.738..31.967 rows = 100000 루프 = 1) |
| Cond : (a = 'a':: text)를 다시 확인하십시오. |
| 인덱스 재검사로 제거 된 행 : 96 |
| 힙 블록 : lossy = 736 |
| -> foo_brin_4의 비트 맵 인덱스 스캔 (비용 = 0.00..862.30 행 = 105907 너비 = 0) (실제 시간 = 2.720..2.720 행 = 7360 루프 = 1) |
| 인덱스 조건 : (a = 'a':: text) |
| 계획 시간 : 0.101 ms |
| 실행 시간 : 52.501ms |
BRIN pages_per_range = 2 :
drop index foo_brin_4;
explain analyze select sum(b) from foo where a='a';
| 쿼리 계획 |
| : ------------------------------------------------- -------------------------------------------------- ----------------------------- |
| 집계 (비용 = 21659.38..21659.39 행 = 1 너비 = 8) (실제 시간 = 53.971..53.971 행 = 1 루프 = 1) |
| -> foo의 비트 맵 힙 스캔 (cost = 952.78..21394.61 rows = 105907 width = 4) (실제 시간 = 5.286..33.492 rows = 100000 루프 = 1) |
| Cond : (a = 'a':: text)를 다시 확인하십시오. |
| 인덱스 재검사로 제거 된 행 : 96 |
| 힙 블록 : lossy = 736 |
| -> foo_brin_2의 비트 맵 인덱스 스캔 (비용 = 0.00..926.30 행 = 105907 너비 = 0) (실제 시간 = 5.275..5.275 행 = 7360 루프 = 1) |
| 인덱스 조건 : (a = 'a':: text) |
| 계획 시간 : 0.095 ms |
| 실행 시간 : 54.016 ms |
진:
drop index foo_brin_2;
explain analyze select sum(b) from foo where a='a';
| 쿼리 계획 |
| : ------------------------------------------------- -------------------------------------------------- ------------------------------ |
| 집계 (비용 = 21687.38..21687.39 행 = 1 너비 = 8) (실제 시간 = 55.331..55.331 행 = 1 루프 = 1) |
| -> foo에서의 비트 맵 힙 스캔 (cost = 980.78..21422.61 rows = 105907 width = 4) (실제 시간 = 12.377..33.956 rows = 100000 루프 = 1) |
| Cond : (a = 'a':: text)를 다시 확인하십시오. |
| 힙 블록 : exact = 736 |
| -> foo_gin에서 비트 맵 인덱스 스캔 (비용 = 0.00..954.30 행 = 105907 너비 = 0) (실제 시간 = 12.271..12.271 행 = 100000 루프 = 1) |
| 인덱스 조건 : (a = 'a':: text) |
| 계획 시간 : 0.118 ms |
| 실행 시간 : 55.366 ms |
여기 dbfiddle