Eu tenho um relacionamento muitos para muitos implementado:
CREATE TABLE public.message (
id BIGSERIAL PRIMARY KEY,
name varchar(40) UNIQUE NOT NULL
);
CREATE TABLE public.package(
id BIGSERIAL PRIMARY KEY,
name varchar(40) UNIQUE NOT NULL
);
CREATE TABLE public.package_to_message (
message_id BIGINT NOT NULL,
package_id BIGINT NOT NULL,
CONSTRAINT package_to_message_pk PRIMARY KEY (message_id, package_id)
);
Preciso selecionar um pacote que esteja associado a um conjunto de mensagens definido com precisão [message_name_1, message_name_2, message_name_3]
. Com todos os itens acima e nada mais. É possível fazer isso usando uma consulta mais ou menos otimizada? Nada vem à mente.
A palavra-chave aqui é “divisão relacional” .
Para as especificações fornecidas, não será mais rápido que isso:
Mas talvez você precise de uma consulta mais genérica/dinâmica...
Chamar:
Minhas consultas pressupõem que você passe nomes de mensagens distintos (sem duplicatas). Além disso,
message.name
está definidoUNIQUE
.Observe como
ANY
eALL
aceite um array ou um conjunto. Ver:Sobre a sintaxe curta
TABLE m
:Índices e desempenho
Índice 1
A
UNIQUE
restrição na tabelamessage
cobre bem a pesquisa.Se o desempenho for crucial (e você atender aos pré-requisitos para varreduras somente de índice), um índice de cobertura seria um pouco melhor:
Ver:
Índice 2
O
PRIMARY KEY
onpackage_to_message(message_id, package_id)
fornece o índice perfeito para a próxima etapa.Índice 3
Idealmente, você adiciona outro índice
package_to_message(package_id, message_id)
para a etapa final. Ver:Com esses três índices em vigor, e se suas tabelas forem limpas o suficiente, ambas as consultas poderão se contentar exclusivamente com varreduras somente de índice. Então leva no máximo alguns ms, mesmo para tabelas grandes, ou até menos de 1 ms de tempo de execução .
--
Relacionado:
Outra opção usa contagens para verificar se temos todas as correspondências. Observe que sua pergunta é especificamente um exemplo de divisão relacional multidirecional sem resto, não com.
Esta é uma variação de uma solução mais generalizada para qualquer Divisão Relacional multidirecional, que é mais eficiente usando um array
Para fazer o mesmo com With Remainder, altere a
HAVING
cláusula paraHAVING count(*) >= (SELECT count(*) FROM inputData);
e altereLEFT JOIN
para aJOIN
.Consulte também este artigo , entre outros, para obter mais opções de Divisão Relacional.