PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Come eseguire query in modo semplice ed efficiente per le relazioni nidificate in SQL?

Come per qualsiasi query, il metodo più efficiente è "dipende". Ci sono molte variabili in gioco:il numero di righe nelle tabelle, la lunghezza delle righe, l'esistenza di indici, la RAM sul server, ecc.

Il modo migliore in cui posso pensare di gestire questo tipo di problema (pensando alla manutenibilità e a un approccio approssimativo all'efficienza) è utilizzare i CTE, che ti consentono di creare un risultato temporaneo e riutilizzarlo durante la query. I CTE utilizzano la parola chiave WITH, ed essenzialmente alias un risultato come una tabella, in modo che tu possa unirti contro di essa più volte:

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)
;

I vantaggi di farlo in questo modo sono:

  1. Ogni CTE può trarre vantaggio da un indice sui predicati JOIN appropriati e restituire risultati solo per quel sottoinsieme più velocemente, piuttosto che fare in modo che il pianificatore dell'esecuzione tenti di risolvere una serie di predicati complessi
  2. I CTE possono essere gestiti individualmente, semplificando la risoluzione dei problemi con i sottoinsiemi
  3. Non stai violando il principio DRY
  4. Se il CTE ha un valore al di fuori della query, puoi spostarlo in una procedura memorizzata e fare riferimento a quella invece