BTree
Meu problema aqui é que o índice BTree será enorme, já que, por padrão, ele armazenará valores duplicados (também, pois não pode assumir que a tabela esteja fisicamente classificada). Se o BTree é enorme, acabo tendo que ler o índice e as partes da tabela que o índice aponta também ...
Não necessariamente - ter um índice de btree 'coberto' será o tempo de leitura mais rápido e, se é tudo o que você deseja (por exemplo, se você puder pagar pelo armazenamento extra), é a sua melhor aposta.
BRIN
Meu entendimento é que eu posso ter um pequeno índice aqui às custas da leitura de páginas inúteis. Usar um pequeno pages_per_range
significa que o índice é maior (o que é um problema com o BRIN, pois preciso ler todo o índice), e ter um grande pages_per_range
significa que vou ler muitas páginas inúteis.
Se você não puder pagar a sobrecarga de armazenamento de um índice btree de cobertura, o BRIN é ideal para você, porque você já possui um cluster (isso é crucial para o BRIN ser útil). Os índices BRIN são pequenos , portanto é provável que todas as páginas estejam na memória se você escolher um valor adequado de pages_per_range
.
Existe uma fórmula mágica para encontrar um bom valor de pages_per_range que leve em consideração essas compensações?
Nenhuma fórmula mágica, mas comece com pages_per_range
um pouco menos do que o tamanho médio (em páginas) ocupado pelo a
valor médio . Você provavelmente está tentando minimizar: (número de páginas BRIN digitalizadas) + (número de páginas heap digitalizadas) para uma consulta típica. Procure Heap Blocks: lossy=n
no plano de execução pages_per_range=1
e compare com outros valores para pages_per_range
- ou seja, veja quantos blocos de heap desnecessários estão sendo varridos.
GIN / GiST
Não tenho certeza de que são relevantes aqui, pois são usados principalmente para pesquisa de texto completo, mas também ouvi dizer que eles são bons em lidar com chaves duplicadas. O GIN
/ GiST
index ajudaria aqui?
Vale a pena considerar o GIN, mas provavelmente não o GiST - no entanto, se o agrupamento natural realmente for bom, o BRIN provavelmente será uma aposta melhor.
Aqui está uma amostra de comparação entre os diferentes tipos de índice para dados fictícios, um pouco como o seu:
tabela e índices:
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;
tamanhos de relação:
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;
nome | tamanho | páginas | linhas / página
: ----------------- | : ------ | ----: | --------:
foo | 149 MB | 19118 135
foo_btree_covering | 56 MB | 7132 364
foo_btree | 56 MB | 7132 364
foo_gin | 2928 kB | 366 7103
foo_brin_2 | 264 kB | 33 78787
foo_brin_4 | 136 kB | 17 152941
cobrindo btree:
explain analyze select sum(b) from foo where a='a';
| PLANO DE CONSULTA |
| : ------------------------------------------------- -------------------------------------------------- ------------------------------------------- |
| Agregado (custo = 3282,57..3282,58 linhas = 1 largura = 8) (tempo real = 45,942..45,942 linhas = 1 loops = 1) |
| -> Somente digitalização de índice usando foo_btree_covering em foo (custo = 0,43..3017,80 linhas = 105907 largura = 4) (tempo real = 0,038..27,286 linhas = 100000 loops = 1) |
| Índice Cond: (a = 'a' :: texto) |
| Buscas de pilha: 0 |
| Tempo de planejamento: 0,099 ms |
| Tempo de execução: 45,968 ms |
btree simples:
drop index foo_btree_covering;
explain analyze select sum(b) from foo where a='a';
| PLANO DE CONSULTA |
| : ------------------------------------------------- -------------------------------------------------- ----------------------------- |
| Agregado (custo = 4064.57..4064.58 linhas = 1 largura = 8) (tempo real = 54.242..54.242 linhas = 1 loops = 1) |
| -> Varredura de índice usando foo_btree on foo (custo = 0,43..3799,80 linhas = 105907 largura = 4) (tempo real = 0,037..33,084 linhas = 100000 loops = 1) |
| Índice Cond: (a = 'a' :: texto) |
| Tempo de planejamento: 0,135 ms |
| Tempo de execução: 54,280 ms |
BRIN pages_per_range = 4:
drop index foo_btree;
explain analyze select sum(b) from foo where a='a';
| PLANO DE CONSULTA |
| : ------------------------------------------------- -------------------------------------------------- ----------------------------- |
| Agregado (custo = 21595,38..21595,39 linhas = 1 largura = 8) (tempo real = 52.455..52.455 linhas = 1 loops = 1) |
| -> Varredura de Heap de Bitmap no foo (custo = 888.78..21330.61 linhas = 105907 largura = 4) (tempo real = 2.738..31.967 linhas = 100000 loops = 1) |
| Verifique novamente Cond: (a = 'a' :: text) |
| Linhas removidas pela verificação do índice: 96 |
| Blocos de heap: com perdas = 736 |
| -> Varredura de índice de bitmap em foo_brin_4 (custo = 0,00..862,30 linhas = 105907 largura = 0) (tempo real = 2,720..2,720 linhas = 7360 loops = 1) |
| Índice Cond: (a = 'a' :: texto) |
| Tempo de planejamento: 0,101 ms |
| Tempo de execução: 52,501 ms |
BRIN pages_per_range = 2:
drop index foo_brin_4;
explain analyze select sum(b) from foo where a='a';
| PLANO DE CONSULTA |
| : ------------------------------------------------- -------------------------------------------------- ----------------------------- |
| Agregado (custo = 21659,38..21659,39 linhas = 1 largura = 8) (tempo real = 53,971..53,971 linhas = 1 loops = 1) |
| -> Varredura de Heap de Bitmap no foo (custo = 952.78..21394.61 linhas = 105907 largura = 4) (tempo real = 5.286..33.492 linhas = 100000 loops = 1) |
| Verifique novamente Cond: (a = 'a' :: text) |
| Linhas removidas pela verificação do índice: 96 |
| Blocos de heap: com perdas = 736 |
| -> Varredura de índice de bitmap em foo_brin_2 (custo = 0,00..926,30 linhas = 105907 largura = 0) (tempo real = 5,275..5,275 linhas = 7360 loops = 1) |
| Índice Cond: (a = 'a' :: texto) |
| Tempo de planejamento: 0,095 ms |
| Tempo de execução: 54,016 ms |
GIN:
drop index foo_brin_2;
explain analyze select sum(b) from foo where a='a';
| PLANO DE CONSULTA |
| : ------------------------------------------------- -------------------------------------------------- ------------------------------ |
| Agregado (custo = 21687.38..21687.39 linhas = 1 largura = 8) (tempo real = 55.331..55.331 linhas = 1 loops = 1) |
| -> Varredura de Heap de Bitmap no foo (custo = 980.78..21422.61 linhas = 105907 largura = 4) (tempo real = 12.377..33.956 linhas = 100000 loops = 1) |
| Verifique novamente Cond: (a = 'a' :: text) |
| Blocos de heap: exato = 736 |
| -> Varredura de índice de bitmap em foo_gin (custo = 0,00..954,30 linhas = 105907 largura = 0) (tempo real = 12,271..12,271 linhas = 100000 loops = 1) |
| Índice Cond: (a = 'a' :: texto) |
| Tempo de planejamento: 0,118 ms |
| Tempo de execução: 55,366 ms |
dbfiddle aqui