Tenho a seguinte consulta:
SELECT * FROM table t
WHERE t.id IN :ids
AND t.id IN :allowedIds
(onde os parâmetros de consulta são substituídos posteriormente)
Esses parâmetros de consulta são otimizados pelo próprio banco de dados? Eu gostaria de evitar ter que mesclar os dois conjuntos de ids juntos no código, pois isso dificulta a legibilidade. A primeira :ids
restrição é o que o próprio usuário passa como filtro e a segunda :allowedIds
restrição é o que o usuário tem acesso. Então, espero que a maioria dos bancos de dados, mas o Postgres em particular, otimize esse tipo de coisa.
Vou ignorar a "maioria dos bancos de dados" nesta questão, caso contrário, teria que votar para fechar por falta de foco. Em vez disso, responderei sobre o PostgreSQL.
Para "mesclar" as listas em sua pergunta, você teria que construir a interseção:
é o mesmo que
O PostgreSQL não faz isso automaticamente. O PostgreSQL pode optar por varrer um índice existente para uma ou ambas as condições, ou pode ir com uma varredura sequencial, mas as duas condições não são mescladas.
Além disso, o PostgreSQL tratará as duas condições como estatisticamente independentes e apenas multiplicará sua seletividade, o que pode resultar em uma estimativa ruim.
Você provavelmente se sairá melhor com uma consulta que tenha uma única
IN
lista, que é a interseção das listas originais.Você perguntou por que a equipe do PostgreSQL não adicionou essa otimização ao código do PostgreSQL, então tenho alguns comentários sobre isso. Este é um requisito bastante incomum (eu tinha entendido mal a pergunta no início), e ao adicionar código otimizador para tais requisitos, há sempre uma troca: enquanto sua consulta se beneficiaria, muitas consultas teriam que pagar o preço na forma de ciclos extras de CPU gastos para testar se a otimização se aplica ou não. Agora, o tempo de planejamento da consulta é uma área bastante sensível (tem que acontecer rápido), então geralmente relutamos em adicionar processamento especial para casos de canto, especialmente se eles podem ser facilmente evitados reescrevendo a consulta.
Também digno de nota: Você pode fazer a interseção no nível SQL se puder passar as listas como arrays e instalar a extensão intarray que permite calcular a interseção entre dois arrays (inteiros!). por exemplo
where id = any(:ids & :allowedIds)