Za předpokladu id
nejen UNIQUE
- jak je vynuceno vaším UNIQUE INDEX
- ale také NOT NULL
. (To v definici tabulky chybí.)
SELECT meta_split.key, meta_split.value, count(*)
FROM voc_cc348779bdc84f8aab483f662a798a6a v
CROSS JOIN LATERAL jsonb_each(v.meta) AS meta_split
GROUP BY meta_split.key, meta_split.value;
Kratší ekvivalent:
SELECT meta_split.key, meta_split.value, count(*)
FROM voc_cc348779bdc84f8aab483f662a798a6a v, jsonb_each(v.meta) AS meta_split
GROUP BY 1, 2;
LEFT [OUTER] JOIN
byl šum, protože následující test WHERE meta_split.value IS NOT NULL
vynutí INNER JOIN
tak jako tak. Pomocí CROSS JOIN
místo toho.
Také, protože jsonb
stejně nepovoluje duplicitní klíče na stejné úrovni (což znamená stejné id
se může zobrazit pouze jednou za (key, value)
), DISTINCT
je jen drahý hluk. count(v.id)
dělá totéž levněji. A count(*)
je ekvivalentní a levnější, přesto - za předpokladu id
je NOT NULL
jak je uvedeno nahoře.
count(*)
má samostatnou implementaci
a je o něco rychlejší než count(<value>)
. Je to nepatrně odlišné od count(v.*)
. Počítá všechny řádky, ať se děje cokoliv. Zatímco druhá forma nepočítá NULL
hodnoty.
Tedy pokud id
nemůže být NULL
- jak je uvedeno nahoře. id
by měl být skutečně PRIMARY KEY
, který je každopádně interně implementován s jedinečným indexem B-stromu, a všechny sloupce - jen id
zde - NOT NULL
implicitně. Nebo alespoň NOT NULL
. UNIQUE INDEX
není plně kvalifikováno jako náhrada, stále umožňuje NULL
hodnoty, které nejsou považovány za stejné a jsou povoleny vícekrát. Viz:
Kromě toho jsou zde indexy k ničemu, protože se stejně musí číst všechny řádky. Takže tohle nikdy nebude moc levné. Ale 62 tisíc řádků není v žádném případě ochromující počet řádků – pokud nemáte velké množství klíčů v jsonb
sloupec.
Zbývající možnosti pro urychlení:
-
Normalizujte svůj design. Rozpojení dokumentů JSON není bezplatné.
-
Udržujte si materializovaný pohled. Proveditelnost a náklady silně závisí na vašich vzorech zápisu.
V tom mohou opět hrát roli indexy ...