Som med enhver forespørgsel er den mest effektive metode "det afhænger". Der er mange variabler i spil - antallet af rækker i tabeller, rækkelængderne, om der findes indekser, RAM på serveren osv. osv.
Den bedste måde, jeg kan komme i tanke om at håndtere denne slags problemer på (at tænke på vedligeholdelse og en god tilgang til effektivitet) er ved at bruge CTE'er, som giver dig mulighed for at skabe et midlertidigt resultat og genbruge det resultat gennem hele din forespørgsel. CTE'er bruger søgeordet WITH og i det væsentlige alias et resultat som en tabel, så du kan JOIN mod det flere gange:
WITH user_memberships AS (
SELECT *
FROM memberships
WHERE user_id = ${id}
), user_apps AS (
SELECT *
FROM apps
INNER JOIN user_memberships
ON user_memberships.team_id = apps.team_id
), user_collections AS (
SELECT *
FROM collections
INNER JOIN user_memberships
ON user_memberships.team_id = collections.team_id
), user_webhooks AS (
SELECT *
FROM webhooks
LEFT OUTER JOIN user_collections ON user_collections.id = webhooks.collection_id
INNER JOIN user_memberships
ON user_memberships.team_id = webhooks.team_id
OR user_memberships.team_id = user_collections.team_id
)
SELECT events.*
FROM events
WHERE app_id IN (SELECT id FROM user_apps)
OR collection_id IN (SELECT id FROM user_collections)
OR membership_id IN (SELECT id FROM user_memberships)
OR team_id IN (SELECT team_id FROM user_memberships)
OR user_id = ${id}
OR webhook_id IN (SELECT id FROM user_webhooks)
;
Fordelene ved at gøre det på denne måde er:
- Hver CTE kan drage fordel af et indeks på de relevante JOIN-prædikater og returnere resultater for netop denne delmængde hurtigere, i stedet for at få udførelsesplanlæggeren til at forsøge at løse en række komplekse prædikater
- CTE'erne kan vedligeholdes individuelt, hvilket gør fejlfinding af problemer med undersæt lettere
- Du overtræder ikke DRY-princippet
- Hvis CTE'en har værdi uden for forespørgslen, kan du flytte den til en lagret procedure og henvise til den i stedet