2008-12-17 17 views
6

que estoy trabajando código PHP de otra persona y ver este patrón una y otra:LEFT JOIN frente a varias instrucciones SELECT

(pseudocódigo)

result = SELECT blah1, blah2, foreign_key FROM foo WHERE key=bar 

if foreign_key > 0 
    other_result = SELECT something FROM foo2 WHERE key=foreign_key 
end 

El código tiene que diversificarse si no hay relacionados remar en la otra tabla, pero ¿no podría hacerse mejor haciendo una unión IZQUIERDA en una sola instrucción SELECT? ¿Me estoy perdiendo algún beneficio de rendimiento? ¿Problema de portabilidad? ¿O acaso solo estoy curioseando?

+0

He estado usando bases de datos SQL desde 1987, pero nunca he tomado cursos SQL. Hasta hace relativamente poco, probablemente lo hubiera hecho de la primera manera porque no sabía muy bien LEFT JOINs. –

+0

¿Esto _really_ necesita nueve más respuestas? – Will

+2

@Will, ¿tiene algo en contra de que todos arrojen su sombrero al anillo de respuestas? Cuantas más respuestas, mejores saldrán a la superficie. – mmcdole

Respuesta

5

No hay suficiente información para responder realmente a la pregunta. He trabajado en aplicaciones donde la disminución del recuento de consultas por una razón y el aumento del recuento de consultas por otra razón ambos dieron mejoras en el rendimiento. En la misma aplicación!

Para ciertas combinaciones de tamaño de tabla, configuración de la base de datos y con qué frecuencia se consultará la tabla externa, hacer las dos consultas puede ser mucho más rápido que una combinación IZQUIERDA. Pero la experiencia y las pruebas son lo único que le dirá que. MySQL con tablas moderadamente grandes parece ser aceptable para esto, IME. Realizar tres consultas en una tabla a menudo puede ser mucho más rápido que una consulta UNIENDO a las tres. He visto aceleraciones de un orden de magnitud.

+0

Gracias, eso es lo que sospechaba. No sé lo suficiente sobre el sistema en cuestión para saber si la elección de codificación fue impulsada por este tipo de preocupación, u otra cosa. Pero es útil saber que podría haber una buena razón para que el desarrollador haga lo que hizo. – zetetic

+0

El hecho de que esto haya sido aceptado me da ganas de llorar ... Si llega a la conclusión de que las selecciones independientes son mejores, transfiera rápidamente su base de datos porque no está haciendo su trabajo. –

+0

Y todas las personas publicando respuestas y comentarios sobre "¡debería ser 1 consulta!" Han olvidado claramente que existe el mundo real. – staticsan

3

estoy contigo - un solo SQL sería mejor

2

Hay un peligro de tratar su DBMS SQL como si fuera un sistema de archivos ISAM, la selección de una sola tabla a la vez. Puede ser más limpio usar un SELECT único con la combinación externa. Por otro lado, detectar nulo en el código de la aplicación y decidir qué hacer en base a nulo vs no nulo tampoco está completamente limpio.

Una de las ventajas de una declaración única: tiene menos viajes redondos al servidor, especialmente si el SQL se prepara dinámicamente cada vez que se necesita el otro resultado.

En promedio, una sola instrucción SELECT es mejor. Le da al optimizador algo que hacer y lo guarda también aburrido.

+0

Sí, debemos mantener el optimizador feliz y realizado. :-) –

2

Me parece que lo que está diciendo es bastante válida - ¿por qué disparar dos llamadas a la base de datos cuando uno va a hacer - (?) A menos que se necesitan dos registros de forma independiente como objetos

Por supuesto, mientras se podría no ser tan simple en cuanto a los códigos retirar todo en una llamada de la base de datos y separar los campos en los dos objetos separados, significa que solo depende de la base de datos para una llamada en lugar de dos ...

Esto sería más agradable de leer como una consulta:

Select a.blah1, a.blah2, b.something From foo a Left Join foo2 b On a.foreign_key = b.key Where a.Key = bar; 

Y de esta forma puede verificar que obtuvo un resultado de una vez y hacer que la base de datos haga todo el trabajo pesado en una consulta en lugar de dos ...

Sí, creo que parece que lo que está diciendo es correcto.

6

Esto definitivamente es incorrecto. Estás revisando el cable una segunda vez sin ningún motivo. Los DB son muy rápidos en su espacio problemático. Unir mesas es uno de esos y verás una mayor degradación del rendimiento a partir de la segunda consulta, luego de la unión. A menos que su espacio de tabla sea de cientos de millones de registros, esta no es una buena idea.

+0

Mi tabla tiene 20 millones de entradas y resultó que la izquierda que se unía a esta tabla era 5s vs 1s con múltiples consultas incl. Tiempo de viaje. – velop

1

Teniendo en cuenta que en una base de datos golpeada tiene todos los datos que necesita con una sola instrucción SQL, se obtendría un mejor rendimiento el 99% del tiempo. No estoy seguro si las conexiones se están creando dinámicamente en este caso o no, pero si hacerlo es costoso. Incluso si el proceso es reutilizar las conexiones existentes, el DBMS no está optimizando las consultas de la mejor manera y no realmente haciendo uso de las relaciones.

La única forma en que podría ver hacer llamadas como esta por motivos de rendimiento es si los datos que se recuperan con la clave externa son una gran cantidad y solo se necesitan en algunos casos. Pero en la muestra que usted describe, simplemente la atrapa si existe, por lo que este no es el caso y, por lo tanto, no obtiene ningún rendimiento.

1

El único "error" de todo esto es si el resultado configurado para trabajar con contiene muchas uniones, o incluso combinaciones anidadas.

Tuve dos o tres instancias en las que la consulta original que heredaba consistía en una sola consulta que tenía muchas combinaciones y que le tomaba al SQL un buen minuto preparar la declaración.

Volví al procedimiento, aproveché algunas variables de tabla (o tablas temporales) y dividí la consulta en muchas de las sentencias de tipo de selección única más pequeñas y construí el conjunto de resultados final de esta manera.

Esta actualización arregló drásticamente el tiempo de respuesta, de unos pocos segundos, porque era más fácil hacer muchos "disparos únicos" para recuperar los datos necesarios.

No estoy tratando de objetar por objeciones aquí, sino solo para señalar que el código puede haberse desglosado a un nivel tan granular para abordar un problema similar.

+0

Buen punto. ¿Y eso no revela una debilidad en el motor de la base de datos? Los programadores no deberían necesitar un SQL-fu tan potente ... – zetetic

+1

No lo llamaría una debilidad en el motor de datos. A veces se encuentra en el programador preguntando cosas absurdas de la base de datos. –

2

La explicación más probable es que el desarrollador simplemente no sabe cómo funcionan las uniones externas. Esto es muy común, incluso entre desarrolladores que tienen bastante experiencia en su propia especialidad.

También existe un mito generalizado de que "las consultas con combinaciones son lentas". Muchos desarrolladores evitan ciegamente las uniones a toda costa, incluso al extremo de ejecutar múltiples consultas donde una sería mejor.

El mito de evitar uniones es como decir que debemos evitar escribir bucles en nuestro código de aplicación, porque ejecutar una línea de código varias veces es obviamente más lento que ejecutarlo una vez. ¡Para no decir nada de la "sobrecarga" de ++i y prueba i<20 durante cada iteración!

+0

Esa fue mi idea también, pero el desarrollador utiliza combinaciones externas en otras partes del sistema, por lo que no es como si fuera completamente ignorante. Excepto por supuesto para el uso de PHP en primer lugar (¡niño! Yo niño!) – zetetic

1

Una sola consulta SQL daría como resultado un mayor rendimiento ya que el servidor SQL (que a veces no comparte la misma ubicación) solo necesita manejar una solicitud; si utiliza múltiples consultas SQL, introduce mucha sobrecarga:

Ejecución más instrucciones de la CPU, el envío de una segunda consulta al servidor, crear un segundo hilo en el servidor, ejecutar posibles más instrucciones de la CPU en el Sever, destruir un segundo hilo en el servidor, enviar el segundo resultados atrás.

Puede haber casos excepcionales en los que el rendimiento sea mejor, pero para cosas simples no se puede alcanzar un mejor rendimiento haciendo un poco más de trabajo.

1

Hacer una simple combinación de dos tablas suele ser la mejor manera de resolver este problema, sin embargo, dependiendo del estado de las tablas y la indexación, hay ciertos casos en los que puede ser mejor hacer las dos declaraciones seleccionadas, pero normalmente no me he encontrado con este problema hasta que empecé a acercarme a 3-5 tablas unidas, no solo a 2.

Solo asegúrese de tener índices de cobertura en ambas tablas para asegurarse de no estar escaneando el disco para todos los registros, ese es el mayor rendimiento alcanzado una base de datos (en mi experiencia limitada)

2

Tiene toda la razón de que la única consulta es el camino a seguir. Para agregar algún valor a las otras respuestas ofrecidas, permítanme agregar este axioma: "Use la herramienta correcta para el trabajo, el servidor de la base de datos debe manejar el trabajo de consulta, el código debe manejar el trabajo de procedimiento".

La idea clave detrás de este concepto es que los optimizadores de compilador/consulta pueden hacer un mejor trabajo si conocen todo el dominio del problema en lugar de la mitad.

1

Siempre debe intentar minimizar el número de consultas a la base de datos cuando pueda. Tu ejemplo es perfecto solo para 1 consulta. De esta forma, más adelante podrá almacenar en caché más fácilmente o gestionar más solicitudes al mismo tiempo, porque en lugar de utilizar siempre 2-3 consultas que requieren una conexión, tendrá solo 1 cada vez.

1

Hay muchos casos que requerirán soluciones diferentes y no es posible explicarlos todos juntos.

Unir explora las tablas y los bucles para que coincida con el primer registro de la tabla en la segunda tabla. La consulta de selección simple funcionará más rápido en muchos casos, ya que solo se preocupan por la clave primaria/única (si existe) para buscar los datos internamente.