BTree
Mein Problem hierbei ist, dass der BTree-Index sehr groß sein wird, da er doppelte Werte speichert (dies ist auch der Fall, da nicht davon ausgegangen werden kann, dass die Tabelle physisch sortiert ist). Wenn der BTree riesig ist, muss ich am Ende sowohl den Index als auch die Teile der Tabelle lesen, auf die der Index ebenfalls verweist ...
Nicht unbedingt - Mit einem Btree-Index, der „abdeckt“, erzielen Sie die schnellste Lesezeit, und wenn Sie nur das möchten (dh wenn Sie sich den zusätzlichen Speicher leisten können), ist dies die beste Wahl.
BRIN
Ich verstehe, dass ich hier einen kleinen Index haben kann, auf Kosten des Lesens nutzloser Seiten. Ein kleiner pages_per_range
Index bedeutet, dass der Index größer ist (was bei BRIN ein Problem ist, da ich den gesamten Index lesen muss) und einen großen Index hatpages_per_range
bedeutet, dass ich viele nutzlose Seiten lesen werde.
Wenn Sie sich den Speicheraufwand für einen abdeckenden Btree-Index nicht leisten können, ist BRIN ideal für Sie, da bereits Clustering vorhanden ist (dies ist für BRIN von entscheidender Bedeutung). BRIN-Indizes sind winzig , sodass sich wahrscheinlich alle Seiten im Arbeitsspeicher befinden, wenn Sie einen geeigneten Wert für auswählen pages_per_range
.
Gibt es eine Zauberformel, um einen guten Wert für pages_per_range zu finden, der diese Kompromisse berücksichtigt?
Keine Zauberformel, aber beginnen Sie mit pages_per_range
etwas weniger als der Durchschnittsgröße (in Seiten), die der Durchschnittswert a
einnimmt. Sie versuchen wahrscheinlich, Folgendes zu minimieren: (Anzahl der gescannten BRIN-Seiten) + (Anzahl der gescannten Heap-Seiten) für eine typische Abfrage. Suchen Sie Heap Blocks: lossy=n
im Ausführungsplan nach pages_per_range=1
und vergleichen Sie sie mit anderen Werten für pages_per_range
- dh sehen Sie, wie viele unnötige Heap-Blöcke gescannt werden.
GIN / GiST
Ich bin mir nicht sicher, ob diese relevant sind, da sie hauptsächlich für die Volltextsuche verwendet werden, aber ich höre auch, dass sie gut mit doppelten Schlüsseln umgehen können. Würde entweder ein GIN
/ GiST
index hier helfen?
GIN ist vielleicht eine Überlegung wert, aber wahrscheinlich nicht GiST. Wenn das natürliche Clustering jedoch wirklich gut ist, ist BRIN wahrscheinlich die bessere Wahl.
Hier ist ein Beispielvergleich zwischen den verschiedenen Indextypen für Dummy-Daten, ähnlich wie bei Ihnen:
Tabelle und Indizes:
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;
Beziehungsgrößen:
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;
name | Größe | seiten | Zeilen / Seite
: ----------------- | : ------ | ----: | --------:
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
btree abdecken:
explain analyze select sum(b) from foo where a='a';
| ANFRAGEPLAN |
| : ------------------------------------------------- -------------------------------------------------- ------------------------------------------- |
| Aggregat (Kosten = 3282,57,3282,58 Zeilen = 1 Breite = 8) (tatsächliche Zeit = 45,942,45,942 Zeilen = 1 Schleifen = 1) |
| -> Nur Index Mit foo_btree_covering auf foo scannen (Kosten = 0,43..3017.80 Zeilen = 105907 Breite = 4) (tatsächliche Zeit = 0,038..27.286 Zeilen = 100000 Schleifen = 1) |
| Indexbedingung: (a = 'a' :: text) |
| Heap Fetches: 0 |
| Planungszeit: 0,099 ms |
| Ausführungszeit: 45.968 ms |
einfacher Baum:
drop index foo_btree_covering;
explain analyze select sum(b) from foo where a='a';
| ANFRAGEPLAN |
| : ------------------------------------------------- -------------------------------------------------- ----------------------------- |
| Aggregat (Kosten = 4064.57..4064.58 Zeilen = 1 Breite = 8) (tatsächliche Zeit = 54.242..54.242 Zeilen = 1 Schleifen = 1) |
| -> Indexsuche mit foo_btree on foo (Kosten = 0,43..3799.80 Zeilen = 105907 Breite = 4) (tatsächliche Zeit = 0,037..33.084 Zeilen = 100000 Schleifen = 1) |
| Indexbedingung: (a = 'a' :: text) |
| Planungszeit: 0,135 ms |
| Ausführungszeit: 54.280 ms |
BRIN pages_per_range = 4:
drop index foo_btree;
explain analyze select sum(b) from foo where a='a';
| ANFRAGEPLAN |
| : ------------------------------------------------- -------------------------------------------------- ----------------------------- |
| Aggregat (Kosten = 21595,38..21595,39 Zeilen = 1 Breite = 8) (tatsächliche Zeit = 52,455..52,455 Zeilen = 1 Schleifen = 1) |
| -> Bitmap-Heap-Scan auf foo (Kosten = 888.78..21330.61 Zeilen = 105907 Breite = 4) (tatsächliche Zeit = 2.738..31.967 Zeilen = 100000 Schleifen = 1) |
| Überprüfen Sie erneut Cond: (a = 'a' :: text) |
| Zeilen vom Index entfernt Erneut prüfen: 96 |
| Heap-Blöcke: verlustbehaftet = 736 |
| -> Bitmap-Index-Scan für foo_brin_4 (Kosten = 0,00..862.30 Zeilen = 105907 Breite = 0) (tatsächliche Zeit = 2.720..2.720 Zeilen = 7360 Schleifen = 1) |
| Indexbedingung: (a = 'a' :: text) |
| Planungszeit: 0,101 ms |
| Ausführungszeit: 52.501 ms |
BRIN pages_per_range = 2:
drop index foo_brin_4;
explain analyze select sum(b) from foo where a='a';
| ANFRAGEPLAN |
| : ------------------------------------------------- -------------------------------------------------- ----------------------------- |
| Aggregat (Kosten = 21659,38..21659,39 Zeilen = 1 Breite = 8) (tatsächliche Zeit = 53,971..53,971 Zeilen = 1 Schleifen = 1) |
| -> Bitmap-Heap-Scan auf foo (Kosten = 952.78..21394.61 Zeilen = 105907 Breite = 4) (tatsächliche Zeit = 5.286..33.492 Zeilen = 100000 Schleifen = 1) |
| Überprüfen Sie erneut Cond: (a = 'a' :: text) |
| Zeilen vom Index entfernt Erneut prüfen: 96 |
| Heap-Blöcke: verlustbehaftet = 736 |
| -> Bitmap-Index-Scan für foo_brin_2 (Kosten = 0,00..926.30 Zeilen = 105907 Breite = 0) (tatsächliche Zeit = 5,275..5.275 Zeilen = 7360 Schleifen = 1) |
| Indexbedingung: (a = 'a' :: text) |
| Planungszeit: 0,095 ms |
| Ausführungszeit: 54.016 ms |
GIN:
drop index foo_brin_2;
explain analyze select sum(b) from foo where a='a';
| ANFRAGEPLAN |
| : ------------------------------------------------- -------------------------------------------------- ------------------------------ |
| Aggregat (Kosten = 21687.38..21687.39 Zeilen = 1 Breite = 8) (tatsächliche Zeit = 55.331..55.331 Zeilen = 1 Schleifen = 1) |
| -> Bitmap-Heap-Scan auf foo (Kosten = 980.78..21422.61 Zeilen = 105907 Breite = 4) (tatsächliche Zeit = 12.377..33.956 Zeilen = 100000 Schleifen = 1) |
| Überprüfen Sie erneut Cond: (a = 'a' :: text) |
| Heap-Blöcke: genau = 736 |
| -> Bitmap-Index-Scan für foo_gin (Kosten = 0,00..954.30 Zeilen = 105907 Breite = 0) (tatsächliche Zeit = 12.271..12.271 Zeilen = 100000 Schleifen = 1) |
| Indexbedingung: (a = 'a' :: text) |
| Planungszeit: 0,118 ms |
| Ausführungszeit: 55.366 ms |
dbfiddle hier