Condições JOIN do Postgres versus condições WHERE

12

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?

Dan
fonte
E a sua versão do Postgres? ( SELECT version();)
Erwin Brandstetter
@ErwinBrandstetter Estou executando o PostgreSQL 9.3.14. Isso deve ser algo que eu exijo em cada função?
Dan
2
Não, nós do dba.SE exigimos que você declare versões de software relevantes, porque elas fazem a diferença para muitas perguntas.
precisa

Respostas:

14

Logicamente , não faz diferença se você coloca condições na cláusula de junção de uma INNER JOINou na WHEREcláusula da mesma SELECT. 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& WHEREcondições em sua busca para o melhor plano de consulta - contanto que o número de tabelas não é maior do que o join_collapse_limit(default 8). Detalhes:

Para legibilidade e manutenção , faz sentido colocar condições que conectam tabelas na respectiva JOINcláusula e condições gerais na WHEREcláusula.

Sua consulta está ótima. Eu usaria aliases de tabela para reduzir o ruído, no entanto.

Detalhe menor:

int2 '1'ou até 1::int2sã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ém 1é boa o suficiente.

Erwin Brandstetter
fonte
2

Alguns pontos ..

  1. Se você estiver ingressando em uma condição com o mesmo nome ( user_id) no seu caso, poderá usar em USING (user_id)vez de ON (a.user_id = b.user_id). Isso também evita que uma coluna redundante seja potencialmente gerada (se você estiver executando SELECT *na produção).

  2. 1::int2é problemático. Ou status, e is_primarye outros estão já int2em 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.

  3. Quando possível, todo o :: int2 provavelmente deve ser armazenado como boolean. Então você pode escrever sua WHEREcondição para ser mais simples também.

  4. Para seu tipo e status, você pode querer um ENUMtipo.

Evan Carroll
fonte