¿Existe alguna diferencia material entre las consultas unidas por las cláusulas WHERE y las consultas que utilizan un JOIN real?

32

En Learn SQL the Hard Way (ejercicio seis) , el autor presenta la siguiente consulta:

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

y luego continúa diciendo que:

En realidad, hay otras formas de hacer que funcionen este tipo de consultas llamadas "combinaciones". Estoy evitando esos conceptos por ahora porque son increíblemente confusos. Simplemente mantén esta forma de unir tablas por ahora e ignora a las personas que intentan decirte que esto es de alguna manera más lento o de "clase baja".

¿Es eso cierto? ¿Por qué o por qué no?

Robert Harvey
fuente
3
No creo que exista, pero puede intentar hacer una EXPLICACIÓN para ver si hay alguna diferencia en la ejecución de la consulta.
GrandmasterB
66
Me gustaría señalar las señales conflictivas de un trabajo con "The Hard Way" en el título omitiendo un concepto "porque son increíblemente confusas". Pero tal vez mi concepto de lo que debería ser "el camino difícil" está mal. Pero de nuevo, tal vez no.
Mindwin
77
JOIN transporta muy bien la intención (unir tablas), esto deja la parte WHERE para los filtros reales y hace que sea un poco más fácil de leer. (además de muchas otras implicaciones)
Th 00 mÄ s
2
¡Está aprendiendo SQL de la manera difícil si el autor no puede molestarse en escribir combinaciones simples! Como ThomasS dice al usar JOINs, las intenciones se hacen más claras y las cláusulas WHERE se vuelven mucho más simples. También el uso de JOIN ilustra mejor la teoría de conjuntos que sustenta SQL.
Daniel Hollinrake
1
No estoy seguro de cómo me siento acerca de algo que pretende enseñarte algo mientras digo "Pero oye, vamos a omitir este concepto fundamental porque son plátanos craaazzzyyyy". Creo que terminaría buscando una fuente diferente para aprender. En algún momento necesitará hacer uniones externas y uniones cruzadas y debe saber cómo hacerlas.
Maurice Reeves

Respuestas:

23

Con el enfoque del autor, enseñar OUTER JOINs será mucho más difícil. La cláusula ON en INNER JOIN nunca fue alucinante para mí como muchas otras cosas. Quizás es porque nunca aprendí a la antigua. Me gustaría pensar que hay una razón por la que nos deshicimos de ella y no fue para presumir y llamar a este método de clase baja.

Es cierto en el escenario muy estrecho que el autor ha creado:

  • Tal nivel de entrada de SQL que usar ON es complejo
  • Solo teniendo en cuenta JOIN / INNER JOIN y no cualquier OUTER JOIN
  • El codificador aislado que no tiene que leer el código de otros ni tiene ninguna persona con experiencia en el uso de ON que lee / usa su código.
  • No requiere consultas complejas con muchas: tablas, if's, but's y or's.

Como parte de una progresión de enseñanza, creo que es más fácil descomponerlo y tener una progresión natural:

Select * from table
select this, something, that from table
select this from table where that = 'this'
select this from table join anothertable on this.id = that.thisid

Los conceptos de unir y filtrar tablas no son realmente los mismos. El aprendizaje de la sintaxis correcta tendrá ahora más arrastre cuando se aprende combinaciones externas a menos que el autor tiene la intención de enseñar / desfasados cosas en desuso como: *= or =*.

JeffO
fuente
55
La razón por la que se agregó la declaración JOIN fue porque no había un estándar para expresar combinaciones externas, por lo que cada proveedor de base de datos tenía su propia sintaxis "especial" (incompatible). IIRC Oracle tenía *=o =*indicaba uniones externas izquierda o derecha, otra que utilicé solo soportaba uniones externas izquierdas con un |=operador.
TMN
1
@TMN IIRC Oracle utilizó +=o tal vez lo fue =+. Creo que *=fue Transact-SQL (Sybase y más tarde MS-SQL). Aún así, buen punto.
David
1
Donde comienza a complicarse (en mi humilde opinión) es cuando tienes una combinación de uniones internas y externas. En ese tipo de situación, confesaré que a veces recurro a la técnica de "clase baja" de realizar mis uniones en la WHEREcláusula. (Escuché que esto se conoce como una combinación theta , pero no estoy seguro de si eso es correcto.)
David
Los operadores de IIRC como "mayor que" o "igual a" a veces se denominaban "operadores theta", pero una búsqueda en Google conduce a alguna operación en el cálculo.
Walter Mitty
12

Si es más lento depende del Optimizador de consultas y de cómo agiliza la consulta (lo que escribe no es realmente lo que se ejecuta). Sin embargo, el gran problema con esta cita es que ignora por completo el hecho de que existen diferentes tipos de combinaciones que funcionan de manera completamente diferente. Por ejemplo, lo que se dice es (en teoría) cierto para inner joins, pero no es cierto para outer joins( left joinsy right joins).

Locke
fuente
9
+1 Para otros tipos de combinaciones. La mayoría de mis uniones son INNER JOINo LEFT OUTER JOIN. No son "increíblemente confusos". SQL puede volverse increíblemente confuso, pero este no es un ejemplo de ello.
mgw854
fuera de tema, pero debe ser la declaración de diferentes tipos de unirse a s o tipos de unirse ?
user1451111
9

El autor presenta un caso simple donde se puede usar la sintaxis antigua o la nueva. No estoy de acuerdo con su afirmación de que las uniones son increíblemente confusas, porque unir tablas es un concepto fundamental de consulta SQL. Entonces, tal vez el autor debería haber pasado algún tiempo antes explicando cómo funciona JOINS antes de pronunciar una declaración obstinada, así como hacer un ejemplo de consulta de múltiples tablas.

Uno debería usar la sintaxis más nueva. El argumento principal para esto es que su consulta tendrá:

  • Seleccionar criterios
  • Unir criterios
  • Criterios de filtro

Utilizando el estilo antiguo, se combinan los criterios de combinación y filtro, que en casos más complejos pueden generar confusión.

Además, uno puede obtener un producto cartesiano olvidando un criterio de unión en la cláusula de filtro:

 person_pet.person_id = person.id

usando la sintaxis anterior.

El uso de la sintaxis más nueva también especifica cómo debe ocurrir la unión, lo que es importante para saber si desea un INNER, LEFT OUTER, etc., por lo que es más explícito en lo que respecta a la sintaxis de JOIN, que en mi humilde opinión aumenta la legibilidad para aquellos que no están familiarizados con las tablas de unión.

Jon Raynor
fuente
5

No debería existir, el analizador de consultas debería generar una representación interna equivalente para consultas equivalentes independientemente de cómo se escriban. El autor solo usa la sintaxis anterior a SQL-92, por lo que menciona que podría verse como "anticuada" o "de clase baja". Internamente, el analizador y el optimizador deberían generar el mismo plan de consulta.

TMN
fuente
5

Aprendí SQL de esta manera, incluida la *=sintaxis para las combinaciones externas. Para mí, fue muy intuitivo ya que todas las relaciones tuvieron la misma prioridad e hicieron un mejor trabajo al configurar consultas como una serie de preguntas: ¿Qué quieres? ¿De dónde los quieres? ¿Cuáles quieres?

Al hacer la joinsintaxis, interrumpe el proceso de pensamiento hacia las relaciones más fuertemente. Y personalmente, encuentro que el código es mucho menos legible con las tablas y las relaciones entremezcladas.

Al menos en MSSQL, no hay una diferencia significativa en el rendimiento de las consultas, suponiendo que use el mismo orden de unión. Dicho esto, hay un problema claro y enorme con el aprendizaje (y el uso) de SQL de esta manera. Si olvida una de sus relaciones, obtendrá productos cruzados inesperados. Lo que en una base de datos de cualquier tamaño no trivial es prohibitivamente costoso (¡y peligroso para los no seleccionados!). Es mucho más difícil olvidar una relación cuando se usa la joinsintaxis de estilo.

Telastyn
fuente
77
Es una base de datos relacional , por lo que las relaciones son bastante importantes para una consulta. Personalmente, me resulta mucho más difícil dar sentido a una consulta que mezcla filtros verdaderos (foo.x = 5) con relaciones (foo.x = bar.x). El motor puede optimizar esto fácilmente en una unión, pero un ser humano esencialmente tiene que razonar sobre esto fila por fila, en lugar de conjuntos y subconjuntos.
Aaronaught
4

Hay dos aspectos diferentes a considerar: Rendimiento y Mantenibilidad / Legibilidad .

Mantenibilidad / legibilidad

Elegí una consulta diferente, ya que creo que es un ejemplo mejor / peor que la consulta original que publicaste.

¿Qué te parece mejor y es más legible?

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e
inner join HumanResources.EmployeeDepartmentHistory edh
on e.BusinessEntityID = edh.BusinessEntityID
inner join HumanResources.Department d
on edh.DepartmentID = d.DepartmentID
where d.Name = 'Engineering';

O...

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e, 
HumanResources.EmployeeDepartmentHistory edh,
HumanResources.Department d
where e.BusinessEntityID = edh.BusinessEntityID
and edh.DepartmentID = d.DepartmentID
and d.Name = 'Engineering';

Para mí personalmente, el primero es bastante legible. Verá que estamos uniendo tablas con INNER JOIN, lo que significa que estamos sacando las filas que coinciden en la cláusula de unión posterior (es decir, "unir Empleado con EmployeeDepartmentHistory en BusinessEntityID e incluir esas filas").

Lo último, la coma no significa nada para mí. Me hace preguntarme qué estás haciendo con todos esos WHEREpredicados de cláusula.

El primero se lee más como piensa mi cerebro. Miro SQL todo el día todos los días y las comas para las uniones. Lo cual me lleva a mi siguiente punto...

En realidad, hay otras formas de hacer funcionar este tipo de consultas llamadas "uniones"

Todos son uniones. Incluso las comas son una combinación. El hecho de que el autor no los llame es su caída ... no es obvio. Debería ser obvio. Usted está uniendo datos relacionales, ya sea que especifique JOINo ,.

Actuación

Definitivamente, esto dependerá de RDBMS. Solo puedo hablar en nombre de Microsoft SQL Server. En cuanto al rendimiento, estos son equivalentes. ¿Cómo lo sabes? Capture los planes posteriores a la ejecución y vea qué está haciendo exactamente SQL Server para cada una de estas declaraciones:

ingrese la descripción de la imagen aquí

En la imagen de arriba, resalté que estoy usando ambas consultas como arriba, que difieren solo en los caracteres explícitos para la unión ( JOINvs ,). SQL Server hace exactamente lo mismo.

Resumen

No uses comas. Usa JOINdeclaraciones explícitas .

Thomas Stringer
fuente
Aprendí INNER JOINs mucho antes de darme cuenta de que la variante con las cláusulas WHERE es equivalente, y ambos ejemplos me parecen muy legibles. El que tiene las WHEREs y las comas podría ser aún más legible. Creo que donde cae es en grandes consultas complejas, no en estas relativamente simples.
Robert Harvey
El punto es que pensar que la variación de coma no es una unión relacional no es correcto en absoluto.
Thomas Stringer el
Creo que estás interpretando incorrectamente las comas como uniones. Las comas simplemente separan tablas; son las condiciones WHERE las que crean las uniones, no las comas.
Robert Harvey
1
Definitivamente puedo decir que no hay unión alguna en las cláusulas predicadas. Creo que estás interpretando incorrectamente las construcciones de tu consulta relacional. ¿Has probado tu coma sin las cláusulas WHERE? Aún funciona. Es una unión cartesiana. ¿Qué crees que estás ganando al usar comas? Por favor, no digas que estás tratando de guardar personajes.
Thomas Stringer el
1
Yo diría que el primero es mejor porque tus intenciones son más claras. Hay mucha menos ambigüedad.
Daniel Hollinrake
4

No, no es cierto en absoluto. El autor está preparando a sus lectores para la confusión y alentando la programación de culto a la carga que evita una diferencia estructural muy poderosa entre la sintaxis estándar y esta variante más antigua que prefiere. Específicamente, una cláusula WHERE desordenada hace que sea más difícil descubrir qué hace que su consulta sea especial.

Su ejemplo lleva a un lector a generar un mapa mental de su significado que tiene un montón de desorden.

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

Aproximadamente, lo anterior es:

Obtenga el ID, NOMBRE, EDAD y MUERTE de la mascota para todas las mascotas, person_pet y personas donde el ID de la mascota coincida con el pet_id de un person_pet, y el person_id de ese registro coincide con el person_id de una persona cuyo FIRST_NAME es "Zed"

Con un mapa mental como ese, el lector (que está escribiendo el SQL a mano por alguna razón) puede cometer un error muy fácilmente, posiblemente omitiendo una o más tablas. Y un lector de código escrito de tal manera tendrá que trabajar más duro, para descubrir exactamente lo que el autor SQL está tratando de hacer. ("Harder" está en el nivel de lectura de SQL con o sin resaltado de sintaxis, pero sigue siendo una diferencia mayor que cero).

Hay una razón por la cual los JOIN son comunes, y es el viejo clásico de "separación de preocupaciones". Específicamente, para una consulta SQL hay una buena razón para separar cómo se estructuran los datos frente a cómo se filtran los datos.

Si la consulta se escribe más limpia, como

SELECT pet.id, pet.name, pet.age
FROM pet
  JOIN person_pet ON pet.id = person_pet.pet_id
  JOIN person ON person.id = person_pet.person_id
WHERE 
  person.first_name = "Zed";

Entonces el lector tiene una distinción más clara entre los componentes de lo que se solicita. El filtro distintivo de esta consulta está separado de cómo se relacionan sus componentes entre sí, y los componentes necesarios de cada relación están directamente al lado de donde se requieren.


Por supuesto, cualquier sistema de base de datos moderno no debería ver una diferencia significativa entre los dos estilos. Pero si el rendimiento de la base de datos fuera la única consideración, la consulta SQL tampoco tendría espacios en blanco ni mayúsculas.

DougM
fuente
2
Desde que escuché este estribillo varias veces, déjame jugar al abogado del diablo. Learn X the Hard Way se trata de tener profundidad técnica; cualquier persona con un buen conocimiento de SQL realmente debería saber que los dos enfoques son equivalentes, en términos del resultado que producen.
Robert Harvey
1
Puedo ver eso, pero el autor no está simplemente afirmando que son declaraciones equivalentes a un servidor SQL decente; afirman que usar JOIN es "confuso", que es un camino por el que espera un código sucio. ("No, no use LINQ, simplemente escriba su declaración FOR a mano". "Al compilador no le importa lo que yo llamo este método, así que no hay razón para no nombrarlo FN1")
DougM
3

Guy está cometiendo un error clásico. Él está tratando de enseñar un concepto abstracto con una implementación específica. Tan pronto como lo haces, te metes en este tipo de lío.

Debería haber enseñado primero los conceptos básicos de la base de datos, luego mostrar SQL como una forma de describirlos.

Izquierda y derecha se unen, se podría argumentar que no importan demasiado. Outer Join, bueno, podrías usar la antigua *=y la =*sintaxis.

Ahora podría argumentar que la sintaxis es más simple, pero solo para consultas simples. Tan pronto como comience a intentar hacer una consulta compleja con esta versión, puede meterse en un desastre horrible. La "nueva" sintaxis no se introdujo para que pudieras hacer consultas complejas, sino para que hagas consultas complejas de una manera legible y, por lo tanto, mantenible.

Tony Hopkinson
fuente
3
"Learn X the Hard Way" es un enfoque de aprendizaje diferente. Escribes el código y luego lo entiendes más tarde.
Robert Harvey
77
@RobertHarvey Ese no es un enfoque de aprendizaje diferente, es el estándar. Más tarde solo sucede si aún estás en su lugar cuando las ruedas se sueltan. trató con demasiadas personas que escriben SQL que piensan que una tabla es una matriz rectangular de celdas para confiar en este método.
Tony Hopkinson
2

El ejemplo es equivalente a la simple reformulación con uniones internas. La diferencia radica únicamente en las posibilidades adicionales que permite la sintaxis JOIN. Por ejemplo, puede especificar el orden en que se procesan las columnas de las dos tablas involucradas; ver por ejemplo https://stackoverflow.com/a/1018825/259310 .

La sabiduría recibida es, en caso de duda, escribir sus consultas de la manera que las haga más legibles. Pero si las formulaciones de JOIN o WHERE son más fáciles de leer parece ser una cuestión de preferencia personal, razón por la cual ambas formas están tan extendidas.

Kilian Foth
fuente
Buena respuesta, aunque usar la WHEREcláusula o ponerla en la JOINdeclaración puede tener un impacto en el rendimiento dependiendo del Optimizador de consultas. Lo he visto suceder más de una vez.
Locke
Mi experiencia con el impacto en el rendimiento es la siguiente: las uniones implícitas permitirán al optimizador de consultas más opciones para optimizar la consulta, lo que puede parecer algo bueno, pero puede ser un problema. Específicamente, el optimizador de consultas puede ajustar la consulta de una manera en desarrollo y otra en producción. Se puede engañar al optimizador para que realice ajustes que reduzcan el rendimiento. Mi recomendación es usar una sintaxis de unión explícita Y confirmar que la unión está usando columnas que tienen índices para que el rendimiento sea predecible.
Michael Potter
2

Cuando aprendí SQL, los formularios INNER JOIN, LEFT JOIN, etc. no existían. Como ya han dicho otras respuestas, diferentes dialectos de SQL implementaron uniones externas utilizando sintaxis idiosincrásica. Esta portabilidad dañada del código SQL. Volver a unir el idioma requirió algún cambio, e IZQUIERDA UNIRSE, etc. fue lo que decidieron.

Es cierto que para cada INNER JOIN, se puede escribir una combinación de coma equivalente con la condición de combinación en la cláusula WHERE. Me tomó un tiempo migrar de que me gustara la forma anterior a preferir la nueva. Aparentemente, el autor de Learning SQL the Hard Way todavía piensa que la manera antigua es más fácil.

¿Hay alguna diferencia? Bueno, si los hay. La primera es que una UNIÓN INTERNA con una cláusula ON revela la intención del autor más claramente que la unión de estilo antiguo. El hecho de que la cláusula ON es de hecho una condición de unión y no algún otro tipo de restricción es más obvio. Esto hace que el código que usa INNER JOIN sea más fácil de aprender al leer que el estilo anterior. Esto es importante cuando se mantiene el código de otra persona.

La segunda diferencia es que el nuevo estilo hace que sea ligeramente más fácil para el optimizador de consultas descubrir la estrategia ganadora. Este es un efecto muy pequeño, pero es real.

La tercera diferencia es que cuando aprendes usando INNER JOIN (o simplemente JOIN) hace que sea más fácil aprender LEFT JOIN, etc.

Aparte de eso, no hay ninguna diferencia material en absoluto.

Walter Mitty
fuente
0

Depende si piensas en términos de conjuntos y lógica formal .....

Si no lo hace, no utilizará la palabra clave "join" para una progresión más simple de la lógica formal a SQL.

Pero si, como el 99% de las personas, no disfrutaba de la lógica formal en su título de matemáticas, entonces la palabra clave de combinación es mucho más fácil de aprender. SQL solía presentarse en la universidad como otra forma de escribir consultas lógicas formales ...

Ian
fuente