Förutsatt id
inte bara UNIQUE
- enligt ditt UNIQUE INDEX
- men också NOT NULL
. (Det saknas i din tabelldefinition.)
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;
Kortare motsvarighet:
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
var brus eftersom följande test WHERE meta_split.value IS NOT NULL
tvingar fram en INNER JOIN
i alla fall. Använder CROSS JOIN
istället.
Dessutom eftersom jsonb
tillåter inte dubbletter av nycklar på samma nivå ändå (vilket betyder samma id
kan bara dyka upp en gång per (key, value)
), DISTINCT
är bara dyrt ljud. count(v.id)
gör detsamma billigare. Och count(*)
är likvärdig och billigare, men ändå - förutsatt id
är NOT NULL
som anges överst.
count(*)
har en separat implementering
och är något snabbare än count(<value>)
. Det skiljer sig subtilt från count(v.*)
. Den räknar alla rader, oavsett vad. Medan den andra formen inte räknas NULL
värden.
Det vill säga så länge som id
kan inte vara NULL
- som det står överst. id
borde verkligen vara PRIMARY KEY
, som implementeras med ett unikt B-trädindex internt ändå, och alla kolumner - bara id
här - är NOT NULL
implicit. Eller åtminstone NOT NULL
. Ett UNIQUE INDEX
inte helt kvalificerar sig som ersättning, den tillåter fortfarande NULL
värden som inte anses lika och som är tillåtna flera gånger. Se:
Bortsett från det är index till ingen nytta här, eftersom alla rader måste läsas ändå. Så det här kommer aldrig att bli särskilt billigt. Men 62 000 rader är inte ett förödande antal rader på något sätt - om du inte har ett stort antal nycklar i jsonb
kolumn.
De återstående alternativen för att påskynda det:
-
Normalisera din design. Att ta bort JSON-dokument är inte gratis.
-
Behåll en materialiserad vy. Genomförbarhet och kostnader beror starkt på dina skrivmönster.
Det är där index kan spela en roll igen ...