¿El uso de la construcción en la cláusula JOIN puede introducir barreras de optimización en ciertos casos?

35

Me llamaron la atención que la USINGconstrucción (en lugar de ON) en la FROMcláusula de SELECTconsultas podría introducir barreras de optimización en ciertos casos.

Me refiero a esta palabra clave:

SELECCIONAR *
A partir de una
ÚNETE b USANDO (a_id)

Solo en casos más complejos.

Contexto: este comentario a esta pregunta .

Lo uso mucho y nunca he notado nada hasta ahora. Estaría muy interesado en un caso de prueba que demuestre el efecto o cualquier enlace a más información. Mis esfuerzos de búsqueda quedaron vacíos.

La respuesta perfecta sería un caso de prueba para mostrar USING (a_id)con un rendimiento inferior en comparación con la cláusula de unión alternativa ON a.a_id = b.a_id, si eso realmente puede suceder.

Erwin Brandstetter
fuente
2
@kgrittn: Eso es lo que generalmente esperaba hasta ahora: eso USINGes un poco más rápido , ya que da como resultado una columna menos en la matriz de resultados. Sus hallazgos se remontan a 2005 y 2008. Supongo que cualquier problema ya se ha solucionado. Sin embargo , puedo ver una posible limitación: las uniones con USINGpueden tener que aplicarse en orden , ya que la columna de unión resultante es un producto conjunto. De este modo, se pueden limitar las opciones de reordenamiento de JOIN.
Erwin Brandstetter
1
Encontré este hilo que puede haber tenido algo que ver con dejar de usarlo tan a menudo como lo hice, porque una VISTA con una condición de USO en una unión puede causar problemas en el volcado / restauración: archives.postgresql.org/pgsql- bugs / 2011-06 / msg00030.php Todavía tengo la sensación persistente de que había otro hilo relacionado con los problemas de rendimiento de USAR donde la solución era usar ON, pero creo que voy a renunciar a encontrarlo. Probablemente sea seguro usarlo fuera de las vistas y solo recuerde intentar ENCENDIDO como paso de diagnóstico si una consulta es lenta.
kgrittn
1
Parece que "usar" hace que el código sea un poco legible, pero supongo que ambos campos necesitan el mismo nombre. No creo que el uso tenga un mejor rendimiento que un "encendido", ya que la base de datos necesita hacer la coincidencia de todos modos, es como si una selección tuviera el mismo rendimiento que una combinación (corríjame si me equivoco), el La diferencia es que Join es más limpio y más fácil de mantener.
jcho360
2
@HLGEM: es solo un nombre simbólico, y con solo dos tablas, como en mi ejemplo, no hay lugar para la confusión. Aún así, modifiqué la pregunta. No quisiera alentar el uso desafortunado de idcomo nombre de columna.
Erwin Brandstetter
2
@ChristiaanWesterbeek: No estoy de acuerdo. El "lugar al que ir" para una respuesta profunda de Postgres es (aún) el envío de correos. Solo muy pocos desarrolladores de Postgres están activos en SO, pero todos los desarrolladores y expertos de Postgres leen la lista de correo
a_horse_with_no_name

Respuestas:

12

Erwin: Estoy de acuerdo con la idea de que USAR causar un pedido rígido podría crear muchos casos extremos en los que se descartarían planes óptimos. Recientemente ayudé a alguien que tenía algo como esto en su consulta:

LEFT JOIN ( 
     a 
     JOIN b ON a.id = b.a_id
     JOIN c ON b.c_id = c.id
) ON a.id = something.a_id
LEFT JOIN (
     table1 t1
     JOIN table2 t2 ON t1.some_field = t2.other_field
     JOIN talbe3 t3 ON t2.yafield = t3.something_else
) ON ....
repeat a few more times

En su caso, el peor de estos bloques de unión estaba causando una unión de bucle anidado a través de unas 200k filas, unas 20k veces (hacer los cálculos), y dado que las teclas no se podían empujar a los índices, era una exploración secuencial. Esto significó que la consulta general tardó aproximadamente 3 horas en ejecutarse debido a cambios en el plan en cascada. Al distribuir la combinación izquierda, las teclas se pueden presionar y la consulta se ejecuta en cuestión de segundos. Por supuesto, esto no es exactamente equivalente, es por eso que el planificador no puede tratarlos como equivalentes, por lo que se dejó descubrir ese plan como una combinación hash y luego hizo un bucle anidado, que fue dolorosamente lento.

Cada vez que fuerza rígidamente a que se unan las uniones en un cierto orden, introduce casos en los que la información clave del filtro puede no estar disponible todavía en la ejecución del plan, y entonces, ¿qué podría hacerse más adelante en una exploración rápida de índice / hash? Es posible que tenga que hacerse mucho más lento en un bucle anidado / exploración secuencial y, si bien el fragmento anterior no es inmediatamente equivalente, muestra el mismo problema.

Chris Travers
fuente