Integra query
Migliorando la logica in più punti, puoi integrare l'intera operazione in un'unica query. Il wrapping in una funzione SQL è facoltativo:
CREATE OR REPLACE FUNCTION f_elems(_action_id integer)
RETURNS SETOF integer AS
$func$
WITH RECURSIVE l AS (
SELECT a.category_id, l.local_id
FROM action a
JOIN local l USING (local_id)
WHERE a.action_id = $1
UNION ALL
SELECT l.category_id, c.local_id
FROM l
JOIN local c ON c.parent_id = l.local_id -- c for "child"
)
SELECT e.element_id
FROM l
JOIN element e USING (category_id, local_id);
$func$ LANGUAGE sql STABLE;
Recupera tutti gli element_id
per gli stessi locali e figli di un dato action_id
.
Chiama:
SELECT * FROM f_elem(3);
element_id
-----------
6
7
Questo dovrebbe essere sostanzialmente già più veloce per diversi motivi. I più ovvi sono:
- Sostituisci l'SQL puro con il ciclo lento in plpgsql.
- Restringere l'insieme iniziale della query ricorsiva.
- Rimuovi
IN
non necessari e notoriamente lenti costruire.
Sto chiamando con SELECT * FROM ...
invece di solo SELECT
, anche se la riga ha una sola colonna, per ottenere il nome della colonna di OUT
parametro (element_id
) ho dichiarato nell'intestazione della funzione.
Più veloce, ancora
Indici
Un indice su action.action_id
è fornito dalla chiave primaria.
Ma potresti aver perso l'indice su local.parent_id
. Mentre ci sei, rendilo un indice a più colonne di copertura (Postgres 9.2+) con parent_id
come primo elemento e local_id
come secondo. Questo dovrebbe aiutare molto se la tabella local
è grande. Non tanto o per niente per un tavolino:
CREATE INDEX l_mult_idx ON local(parent_id, local_id);
Come mai? Vedi:
Infine, un indice multicolonna
sulla tabella element
dovrebbe aiutare un po' di più:
CREATE INDEX e_mult_idx ON element (category_id, local_id, element_id);
La terza colonna element_id
è utile solo per renderlo un indice di copertura . Se la tua query recupera più colonne dalla tabella element
, potresti voler aggiungere più colonne all'indice o rilasciare element_id
. O lo renderà più veloce.
Vista materializzata
Se le tue tabelle ricevono pochi o nessun aggiornamento, una vista materializzata che fornisce l'insieme precalcolato di tutte le coppie (action_id, element_id)
condividere la stessa categoria renderebbe questo fulmineo . Crea (action_id, element_id)
(in quest'ordine) la chiave primaria.