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 ...