Integrar consulta
Melhorando a lógica em vários lugares, você pode integrar toda a operação em uma única consulta. Agrupar em uma função SQL é opcional:
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 todos os
element_id
para mesmo local e local filho de um determinado action_id
. Ligar:
SELECT * FROM f_elem(3);
element_id
-----------
6
7
db<>fiddle aqui
ANTIGO sqlfiddle
Isso deve ser substancialmente mais rápido já por várias razões. As mais óbvias são:
- Substitua o SQL puro por loop lento no plpgsql.
- Restringir o conjunto inicial da consulta recursiva.
- Remover desnecessário e notoriamente lento
IN
construir.
Estou ligando com
SELECT * FROM ...
em vez de apenas SELECT
, mesmo que a linha tenha apenas uma coluna, para obter o nome da coluna do OUT
parâmetro (element_id
) declarei no cabeçalho da função. Mais rápido, ainda
Índices
Um índice em
action.action_id
é fornecido pela chave primária. Mas você pode ter perdido o índice em
local.parent_id
. Enquanto isso, faça disso um índice de várias colunas (Postgres 9.2+) com parent_id
como primeiro elemento e local_id
como segundo. Isso deve ajudar muito se a tabela local
é grande. Nem tanto ou nada para uma mesa pequena:CREATE INDEX l_mult_idx ON local(parent_id, local_id);
Por quê? Ver:
Por fim, um índice de várias colunas na tabela
element
deve ajudar um pouco mais:CREATE INDEX e_mult_idx ON element (category_id, local_id, element_id);
A terceira coluna
element_id
só é útil para torná-lo um índice de cobertura . Se sua consulta recuperar mais colunas da tabela element
, você pode querer adicionar mais colunas ao índice ou remover element_id
. Qualquer um vai torná-lo mais rápido. Visão materializada
Se suas tabelas recebem poucas ou nenhuma atualização, uma visão materializada fornecendo o conjunto pré-computado de todos os pares
(action_id, element_id)
compartilhar a mesma categoria tornaria isso muito rápido . Faça (action_id, element_id)
(nessa ordem) a chave primária.