Condiciones de Postgres JOIN vs.

12

Postgres novato aquí.

Me pregunto si esta consulta está optimizada o no. Intenté unirme solo a los valores que son 100% necesarios y dejar todas las condiciones dinámicas en la cláusula WHERE. Vea abajo.

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: Para el contexto, este proceso está verificando si un usuario también es un empleado (privilegios elevados / tipo de usuario diferente).

De todos modos, ¿es este el camino correcto? ¿Debería JOIN ON contener más sentencias como, por ejemplo, comprobar expired_at IS NULL? ¿Por qué o por qué esto no tiene sentido?

Dan
fuente
¿Qué hay de tu versión de Postgres? ( SELECT version();)
Erwin Brandstetter
@ErwinBrandstetter Estoy ejecutando PostgreSQL 9.3.14. ¿Debería ser esto algo que requiero en cada función?
Dan
2
No, aquí en dba.SE le exigimos que declare las versiones de software relevantes, porque marcan la diferencia en muchas preguntas.
Erwin Brandstetter

Respuestas:

14

Lógicamente , no hace ninguna diferencia si coloca condiciones en la cláusula de unión de una INNER JOINo en la WHEREcláusula de la misma SELECT. El efecto es el mismo.

(¡No es el caso OUTER JOIN!)

Mientras opera con la configuración predeterminada, tampoco hay diferencia para el plan de consulta o el rendimiento . Postgres es libre para reorganizar y se une JOINy WHEREcondiciones en su búsqueda de la mejor plan de consulta - siempre y cuando el número de tablas no es mayor que el join_collapse_limit(por defecto 8). Detalles:

Para facilitar la lectura y la mantenibilidad , tiene sentido colocar condiciones que conecten tablas en la JOINcláusula respectiva y condiciones generales en la WHEREcláusula.

Su consulta se ve bien. Sin embargo, usaría alias de tabla para reducir el ruido.

Detalle menor:

int2 '1'o incluso 1::int2son más sensibles que (1)::INT2. Y mientras se compara con un valor de tipo de datos numéricos bien definido, una constante numérica simple también 1es suficiente.

Erwin Brandstetter
fuente
2

Un par de puntos ...

  1. Si se une a una condición con el mismo nombre ( user_id) en su caso, puede usar en USING (user_id)lugar de ON (a.user_id = b.user_id). Esto también evita que una columna redundante se emita potencialmente (si está SELECT *en producción).

  2. 1::int2es problemático O bien status, y is_primaryotros ya están int2en cuyo caso el literal 1 se convertirá automáticamente en int2, o int2 se convertirá en int como pg lo crea conveniente. O bien, si los almacena como entradas regulares y los rechaza como si eso hiciera una diferencia en el cálculo, lo que no es así, solo el elenco lo convierte en una propuesta perdedora.

  3. Cuando sea posible, todos los :: int2 probablemente deberían almacenarse como boolean. Entonces puedes escribir tu WHEREcondición para que sea más simple también.

  4. Para su tipo y estado, es posible que desee un ENUMtipo.

Evan Carroll
fuente