Intégrer la requête
Améliorant la logique à plusieurs endroits, vous pouvez intégrer l'ensemble de l'opération dans une seule requête. L'encapsulation dans une fonction SQL est facultative :
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;
Récupère tous les element_id
pour le même et les enfants locaux d'un action_id
donné .
Appel :
SELECT * FROM f_elem(3);
element_id
-----------
6
7
db<>violon ici
ANCIEN sqlfiddle
Cela devrait être substantiellement déjà plus vite pour plusieurs raisons. Les plus évidents étant :
- Remplacez le SQL pur par une boucle lente dans plpgsql.
- Réduire l'ensemble de départ de la requête récursive.
- Supprimez les
IN
inutiles et notoirement lents construire.
J'appelle avec SELECT * FROM ...
au lieu de simplement SELECT
, même si la ligne n'a qu'une seule colonne, pour obtenir le nom de la colonne de OUT
paramètre (element_id
) J'ai déclaré dans l'en-tête de la fonction.
Plus rapide, mais
Indices
Un index sur action.action_id
est fourni par la clé primaire.
Mais vous avez peut-être manqué l'index sur local.parent_id
. Pendant que vous y êtes, faites-en un index multi-colonnes couvrant (Postgres 9.2+) avec parent_id
comme premier élément et local_id
comme deuxième. Cela devrait beaucoup aider si la table local
est grand. Pas tellement ou pas du tout pour une petite table :
CREATE INDEX l_mult_idx ON local(parent_id, local_id);
Pourquoi? Voir :
Enfin, un index multi-colonnes
sur la table element
devrait aider un peu plus :
CREATE INDEX e_mult_idx ON element (category_id, local_id, element_id);
La troisième colonne element_id
n'est utile que pour en faire un index de couverture . Si votre requête récupère plus de colonnes de la table element
, vous pouvez ajouter plus de colonnes à l'index ou supprimer element_id
. L'un ou l'autre le rendra plus rapide.
Vue matérialisée
Si vos tables reçoivent peu ou pas de mises à jour, une vue matérialisée fournissant l'ensemble pré-calculé de toutes les paires (action_id, element_id)
partager la même catégorie rendrait cela rapide comme l'éclair . Faire (action_id, element_id)
(dans cet ordre) la clé primaire.