Forudsat id
ikke kun UNIQUE
- som håndhævet af din UNIQUE INDEX
- men også NOT NULL
. (Det mangler i din tabeldefinition.)
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;
Kortere ækvivalent:
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 støj, fordi følgende test WHERE meta_split.value IS NOT NULL
fremtvinger en INNER JOIN
alligevel. Brug af CROSS JOIN
i stedet.
Også da jsonb
tillader ikke duplikerede nøgler på samme niveau alligevel (det betyder det samme id
kan kun dukke op én gang pr. (key, value)
), DISTINCT
er bare dyr støj. count(v.id)
gør det samme billigere. Og count(*)
er ækvivalent og billigere, men alligevel - forudsat id
er NOT NULL
som angivet øverst.
count(*)
har en separat implementering
og er lidt hurtigere end count(<value>)
. Det er subtilt forskelligt fra count(v.*)
. Det tæller alle rækker, uanset hvad. Mens den anden form ikke tæller NULL
værdier.
Det vil sige, så længe id
kan ikke være NULL
- som der står øverst. id
burde virkelig være den PRIMARY KEY
, som alligevel er implementeret med et unikt B-træindeks internt, og alle kolonner - kun id
her - er NOT NULL
implicit. Eller i det mindste NOT NULL
. Et UNIQUE INDEX
ikke fuldt ud kvalificeres som erstatning, tillader den stadig NULL
værdier, der ikke betragtes som ens og er tilladt flere gange. Se:
Ud over det er indekser til ingen nytte her, da alle rækker skal læses alligevel. Så det bliver aldrig særlig billigt. Men 62.000 rækker er på ingen måde et lammende rækkeantal - medmindre du har et stort antal nøgler i jsonb
kolonne.
De resterende muligheder for at fremskynde det:
-
Normaliser dit design. Det er ikke gratis at fjerne JSON-dokumenter.
-
Oprethold et materialiseret syn. Gennemførlighed og omkostninger afhænger stærkt af dine skrivemønstre.
Det er her indekser kan spille en rolle igen ...