Integrera fråga
Genom att förbättra logiken på flera ställen kan du integrera hela operationen i en enda fråga. Att slå in i en SQL-funktion är valfritt:
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;
Hämtar alla element_id för samma och underordnade lokalbefolkningen av en given action_id .
Ring:
SELECT * FROM f_elem(3);
element_id
-----------
6
7
Detta bör vara väsentligt snabbare redan av flera anledningar. De mest uppenbara är:
- Ersätt ren SQL för långsam looping i plpgsql.
- Begränsa startuppsättningen för den rekursiva frågan.
- Ta bort onödiga och notoriskt långsamma
INkonstruera.
Jag ringer med SELECT * FROM ... istället för bara SELECT , även om raden bara har en enda kolumn, för att få kolumnnamnet för OUT parameter (element_id ) Jag deklarerade i funktionshuvudet.
Snabbare men ändå
Indeks
Ett index på action.action_id tillhandahålls av primärnyckeln.
Men du kanske har missat indexet på local.parent_id . Medan du håller på, gör det till ett täckande index med flera kolumner (Postgres 9.2+) med parent_id som första element och local_id som tvåa. Detta borde hjälpa mycket om tabellen local är stor. Inte så mycket eller inte alls för ett litet bord:
CREATE INDEX l_mult_idx ON local(parent_id, local_id);
Varför? Se:
Slutligen ett flerkolumnindex
i tabellen element borde hjälpa lite mer:
CREATE INDEX e_mult_idx ON element (category_id, local_id, element_id);
Den tredje kolumnen element_id är bara användbart för att göra det till ett täckande index . Om din fråga hämtar fler kolumner från tabellen element , kanske du vill lägga till fler kolumner i indexet eller släppa element_id . Båda kommer att göra det snabbare.
Materialiserad vy
Om dina tabeller får få eller inga uppdateringar, en materialiserad vy som ger den förberäknade uppsättningen av alla par (action_id, element_id) att dela samma kategori skulle göra detta blixtsnabbt . Gör (action_id, element_id) (i den ordningen) primärnyckeln.