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