Novato no Postgres aqui.
Gostaria de saber se esta consulta está otimizada ou não? Tentei JOIN ON apenas os valores que são 100% necessários e deixando todas as condições dinâmicas na cláusula WHERE. Ver abaixo.
SELECT *
FROM
myapp_employees
JOIN myapp_users ON
myapp_users.user_id=myapp_employees.user_id
JOIN myapp_contacts_assoc ON
myapp_contacts_assoc.user_id=myapp_users.user_id
JOIN myapp_contacts ON
myapp_contacts.contact_id=myapp_contacts_assoc.contact_id
WHERE
myapp_contacts.value='[email protected]' AND
myapp_contacts.type=(1)::INT2 AND
myapp_contacts.is_primary=(1)::INT2 AND
myapp_contacts.expired_at IS NULL AND
myapp_employees.status=(1)::INT2 AND
myapp_users.status=(1)::INT2
LIMIT 1;
Nota: Por contexto, este processo está verificando se um usuário também é um funcionário (privs elevados / tipo de usuário diferente).
Enfim, este é o caminho certo a seguir? O JOIN ON deve conter mais instruções, como a verificação de expired_at IS NULL, por exemplo? Por que ou por que isso não faz sentido?
SELECT version();
)Respostas:
Logicamente , não faz diferença se você coloca condições na cláusula de junção de uma
INNER JOIN
ou naWHERE
cláusula da mesmaSELECT
. O efeito é o mesmo.(Não é o caso
OUTER JOIN
!)Ao operar com configurações padrão, também não faz diferença para o plano ou desempenho da consulta . Postgres é livre para reorganizar junta e
JOIN
&WHERE
condições em sua busca para o melhor plano de consulta - contanto que o número de tabelas não é maior do que ojoin_collapse_limit
(default8
). Detalhes:Para legibilidade e manutenção , faz sentido colocar condições que conectam tabelas na respectiva
JOIN
cláusula e condições gerais naWHERE
cláusula.Sua consulta está ótima. Eu usaria aliases de tabela para reduzir o ruído, no entanto.
Detalhe menor:
int2 '1'
ou até1::int2
são mais sensatos que(1)::INT2
. E, ao comparar com um valor de tipo de dados numérico bem definido, uma constante numérica simples também1
é boa o suficiente.fonte
Alguns pontos ..
Se você estiver ingressando em uma condição com o mesmo nome (
user_id
) no seu caso, poderá usar emUSING (user_id)
vez deON (a.user_id = b.user_id)
. Isso também evita que uma coluna redundante seja potencialmente gerada (se você estiver executandoSELECT *
na produção).1::int2
é problemático. Oustatus
, eis_primary
e outros estão jáint2
em cujo caso o literal 1 será automaticamente escalado para int2, ou int2 escalado para int como pg aprouver. Ou, se você as armazena como entradas regulares e as descarta como se isso fizesse diferença na computação - o que não acontece, o elenco por si só faz disso uma proposta perdida.Quando possível, todo o :: int2 provavelmente deve ser armazenado como
boolean
. Então você pode escrever suaWHERE
condição para ser mais simples também.Para seu tipo e status, você pode querer um
ENUM
tipo.fonte