BTree
Mi problema aquí es que el índice BTree será enorme ya que, en caso de que ocurra, almacenará valores duplicados (también lo tiene, ya que no puede asumir que la tabla está físicamente ordenada). Si BTree es enorme, termino teniendo que leer tanto el índice como las partes de la tabla que el índice también señala ...
No necesariamente: tener un índice btree que 'cubra' será el tiempo de lectura más rápido, y si eso es todo lo que desea (es decir, si puede permitirse el almacenamiento adicional), entonces es su mejor opción.
BRIN
Tengo entendido que puedo tener un pequeño índice aquí a expensas de leer páginas inútiles. Usar un pequeño pages_per_range
significa que el índice es más grande (lo cual es un problema con BRIN ya que necesito leer todo el índice), y tener un gran pages_per_range
medio significa que leeré muchas páginas inútiles.
Si no puede permitirse la sobrecarga de almacenamiento de un índice btree de cobertura, BRIN es ideal para usted, porque ya tiene una agrupación (esto es crucial para que BRIN sea útil). Los índices BRIN son pequeños , por lo que es probable que todas las páginas estén en la memoria si elige un valor adecuado de pages_per_range
.
¿Existe una fórmula mágica para encontrar un buen valor de pages_per_range que tenga en cuenta esas compensaciones?
No hay fórmula mágica, pero comienza con pages_per_range
algo menos que el tamaño promedio (en páginas) ocupado por el a
valor promedio . Probablemente esté intentando minimizar: (número de páginas BRIN escaneadas) + (número de páginas de montón escaneadas) para una consulta típica. Busque Heap Blocks: lossy=n
en el plan de ejecución pages_per_range=1
y compare con otros valores para pages_per_range
, es decir, vea cuántos bloques de montón innecesarios se están escaneando.
GIN / GiST
No estoy seguro de que sean relevantes aquí, ya que se usan principalmente para la búsqueda de texto completo, pero también escuché que son buenos para manejar claves duplicadas. ¿Ayudaría a GIN
/ GiST
index aquí?
Puede valer la pena considerar GIN, pero probablemente no GiST; sin embargo, si el agrupamiento natural es realmente bueno, entonces BRIN probablemente será una mejor apuesta.
Aquí hay una comparación de muestra entre los diferentes tipos de índice para datos ficticios un poco como el suyo:
tabla 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;
tamaños de relación:
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;
nombre | tamaño | páginas | filas / 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
cubriendo btree:
explain analyze select sum(b) from foo where a='a';
El | PLAN DE CONSULTA |
El | : ------------------------------------------------- -------------------------------------------------- ------------------------------------------- |
El | Agregado (costo = 3282.57..3282.58 filas = 1 ancho = 8) (tiempo real = 45.942..45.942 filas = 1 bucles = 1) |
El | -> Escaneo de índice solamente usando foo_btree_covering en foo (costo = 0.43..3017.80 filas = 105907 ancho = 4) (tiempo real = 0.038..27.286 filas = 100000 bucles = 1) |
El | Índice Cond: (a = 'a' :: texto) |
El | Capturas del montón: 0 |
El | Tiempo de planificación: 0.099 ms |
El | Tiempo de ejecución: 45.968 ms |
btree simple:
drop index foo_btree_covering;
explain analyze select sum(b) from foo where a='a';
El | PLAN DE CONSULTA |
El | : ------------------------------------------------- -------------------------------------------------- ----------------------------- |
El | Agregado (costo = 4064.57..4064.58 filas = 1 ancho = 8) (tiempo real = 54.242..54.242 filas = 1 bucles = 1) |
El | -> Escaneo de índice usando foo_btree en foo (costo = 0.43..3799.80 filas = 105907 ancho = 4) (tiempo real = 0.037..33.084 filas = 100000 bucles = 1) |
El | Índice Cond: (a = 'a' :: texto) |
El | Tiempo de planificación: 0.135 ms |
El | Tiempo de ejecución: 54.280 ms |
BRIN páginas_por_rango = 4:
drop index foo_btree;
explain analyze select sum(b) from foo where a='a';
El | PLAN DE CONSULTA |
El | : ------------------------------------------------- -------------------------------------------------- ----------------------------- |
El | Agregado (costo = 21595.38..21595.39 filas = 1 ancho = 8) (tiempo real = 52.455..52.455 filas = 1 bucles = 1) |
El | -> Bitmap Heap Scan en foo (costo = 888.78..21330.61 filas = 105907 ancho = 4) (tiempo real = 2.738..31.967 filas = 100000 bucles = 1) |
El | Vuelva a verificar Cond: (a = 'a' :: texto) |
El | Filas eliminadas por la comprobación de índice: 96 |
El | Bloques de montón: con pérdida = 736 |
El | -> Escaneo de índice de mapa de bits en foo_brin_4 (costo = 0.00..862.30 filas = 105907 ancho = 0) (tiempo real = 2.720..2.720 filas = 7360 bucles = 1) |
El | Índice Cond: (a = 'a' :: texto) |
El | Tiempo de planificación: 0.101 ms |
El | Tiempo de ejecución: 52.501 ms |
BRIN páginas_por_rango = 2:
drop index foo_brin_4;
explain analyze select sum(b) from foo where a='a';
El | PLAN DE CONSULTA |
El | : ------------------------------------------------- -------------------------------------------------- ----------------------------- |
El | Agregado (costo = 21659.38..21659.39 filas = 1 ancho = 8) (tiempo real = 53.971..53.971 filas = 1 bucles = 1) |
El | -> Bitmap Heap Scan en foo (costo = 952.78..21394.61 filas = 105907 ancho = 4) (tiempo real = 5.286..33.492 filas = 100000 bucles = 1) |
El | Vuelva a verificar Cond: (a = 'a' :: texto) |
El | Filas eliminadas por la comprobación de índice: 96 |
El | Bloques de montón: con pérdida = 736 |
El | -> Escaneo de índice de mapa de bits en foo_brin_2 (costo = 0.00..926.30 filas = 105907 ancho = 0) (tiempo real = 5.275..5.275 filas = 7360 bucles = 1) |
El | Índice Cond: (a = 'a' :: texto) |
El | Tiempo de planificación: 0.095 ms |
El | Tiempo de ejecución: 54.016 ms |
GINEBRA:
drop index foo_brin_2;
explain analyze select sum(b) from foo where a='a';
El | PLAN DE CONSULTA |
El | : ------------------------------------------------- -------------------------------------------------- ------------------------------ |
El | Agregado (costo = 21687.38..21687.39 filas = 1 ancho = 8) (tiempo real = 55.331..55.331 filas = 1 bucles = 1) |
El | -> Bitmap Heap Scan en foo (costo = 980.78..21422.61 filas = 105907 ancho = 4) (tiempo real = 12.377..33.956 filas = 100000 bucles = 1) |
El | Vuelva a verificar Cond: (a = 'a' :: texto) |
El | Bloques de montón: exactos = 736 |
El | -> Escaneo de índice de mapa de bits en foo_gin (costo = 0.00..954.30 filas = 105907 ancho = 0) (tiempo real = 12.271..12.271 filas = 100000 bucles = 1) |
El | Índice Cond: (a = 'a' :: texto) |
El | Tiempo de planificación: 0.118 ms |
El | Tiempo de ejecución: 55.366 ms |
dbfiddle aquí