2009-10-21 21 views
45

tengo mi negocio en la lógica de ~ 7000 líneas de procedimientos almacenados de T-SQL, y la mayoría de ellos tiene al lado JOIN sintaxis:ANSI vs. no ANSI SQL JOIN sintaxis

SELECT A.A, B.B, C.C 
FROM aaa AS A, bbb AS B, ccc AS C 
WHERE 
    A.B = B.ID 
AND B.C = C.ID 
AND C.ID = @param 

Voy a recibir el rendimiento de crecimiento si voy a reemplazar dicha consulta con esto:

SELECT A.A, B.B, C.C 
FROM aaa AS A 
JOIN bbb AS B 
    ON A.B = B.ID 
JOIN ccc AS C 
    ON B.C = C.ID 
    AND C.ID = @param 

¿O son lo mismo?

+0

No sé por qué editó el título: ahora contiene errores. Ambas consultas son combinaciones y sus respectivas sintaxis están consagradas en el Estándar SQL-92. Tenga en cuenta que el estándar es internacional (ISO) además de ser estadounidense (ANSI). – onedaywhen

+2

Del artículo de Wikipedia sobre [SQL] (http://en.wikipedia.org/wiki/SQL): "SQL fue adoptado como estándar por el Instituto Nacional de Estándares Americanos (ANSI) en 1986 como SQL-86 y el International. Organización para la Normalización (ISO) en 1987. " En la literatura, el calificador ISO/IEC parece ser mucho más común que ANSI; Creo que ANSI es frecuente en foros como Stackoverflow porque los productos como SQL Server y MySQL tienen palabras clave que usan la palabra "ANSI", p. ANSI_NULLS (no tengo idea de por qué no usan "ISO"); aunque estas son mis propias observaciones, dudo que sean pensamientos originales;) – onedaywhen

+0

Tenga en cuenta que cada Estándar adopta (y agrega) las características del SQL Estándar anterior, de modo que las características del SQL Estándar nunca se desaprobaron, a lo que Hugh Darwen se refiere el [* Grillete de compatibilidad *] (http://www.dcs.warwick.ac.uk/~hugh/TTM/HAVING-A-Blunderful-Time.html). – onedaywhen

Respuesta

63

Las dos consultas son los mismos, excepto el segundo es ANSI-92 sintaxis SQL y la primera es la sintaxis SQL mayores que no incorporan la cláusula de combinación. Deben generar exactamente el mismo plan de consulta interno, aunque es posible que desee verificarlo.

Se debe utilizar la sintaxis ANSI-92 para varios de razones

  • El uso de la cláusula JOIN separa la lógica relación desde el lógica del filtro (el dónde) y es por tanto limpio y fácil de entender.
  • No importa con esta consulta en particular, pero hay algunas circunstancias donde la sintaxis de unión externa anterior (usando +) es ambigua y los resultados de la consulta dependen de la implementación, o la consulta no se puede resolver en absoluto. Esto no ocurre con ANSI-92
  • Es una buena práctica ya que la mayoría de los desarrolladores y dba utilizarán ANSI-92 hoy en día y usted debe seguir el estándar. Ciertamente, todas las herramientas de consulta modernas generarán ANSI-92.
  • Según lo señalado por @gbn, tiende a evitar uniones cruzadas accidentales.

Yo me resistía ANSI-92 desde hace algún tiempo ya que hay una ligera ventaja conceptual a la sintaxis de edad, ya que es una más fácil de prever la SQL como cartesiana masa unión de todas las tablas utilizadas seguido de una operación de filtrado - una técnica mental que puede ser útil para captar lo que está haciendo una consulta SQL. Sin embargo, hace algunos años decidí que tenía que moverme con los tiempos y, después de un período de ajuste relativamente corto, ahora lo prefiero mucho, sobre todo por la primera razón dada anteriormente. El único lugar donde uno debe partir de la sintaxis ANSI-92, o más bien no usar la opción, es con combinaciones naturales que son implícitamente peligrosas.

+16

¿Puedo agregar: ayuda a evitar las uniones cruzadas accidentales ... – gbn

+1

Tuve una pendiente similar a la de hace 10 años dejando atrás la forma antigua de coma/igual de unión, pero no hemos mirado hacia atrás. –

+1

Al examinar una consulta grande, es útil ver la lógica de unión muy cerca de las tablas relevantes. La sintaxis anterior puede requerir un gran desplazamiento hacia arriba y hacia abajo para examinar las tablas y los predicados juntos. – durette

3

Ejecute ambos y compruebe sus planes de consulta. Ellos deben ser iguales.

+2

+1 para usar las herramientas de análisis. Recomendaría mirar: para más formas "llenas de azúcar" de especificar uniones. Deje que los estándares sean su guía, pero recuerde que su implementación particular de DBs es la ruta (y afortunadamente no es MySQL :) –

3

Las dos consultas son iguales - la primera usa sintaxis ANSI JOIN, la 2 es la sintaxis ANSI JOIN. Recomiendo seguir con la sintaxis ANSI JOIN.

Y sí, LEFT OUTER JOINs (que, por cierto también son sintaxis ANSI JOIN) es lo que desea utilizar cuando existe la posibilidad de que la tabla a la que se une no contenga ningún registro coincidente.

Referencia: Conditional Joins in SQL Server

4

La segunda construcción se conoce como la "sintaxis de unión infija" en la comunidad SQL. El primer constructo AFAIK no tiene un nombre ampliamente aceptado, así que vamos a llamarlo la sintaxis de unión interna de "estilo antiguo".

Los argumentos habituales algo así:

Ventajas de la sintaxis 'tradicional': los predicados se agrupan físicamente juntos en la cláusula WHERE en cualquier orden que hace la consulta general, y n-arias relaciones particular , más fácil de leer y entender (las cláusulas ON de la sintaxis infija pueden extender los predicados, por lo que debe buscar la apariencia de una tabla o columna sobre una distancia visual).

Contras de la sintaxis 'Tradicional': No hay error de análisis al omitir uno de los predicados 'unirse' y el resultado es un producto cartesiano (conocido como CROSS JOIN en la sintaxis infija) y tal error puede ser complicado para detectar y depurar. Además, los predicados 'join' y 'filtrado' se agrupan físicamente en la cláusula WHERE, lo que puede hacer que se confundan entre sí.

0

La sintaxis ANSI no impone la colocación de predicados en la cláusula adecuada (ya sea ON o WHERE) ni la afinidad de la cláusula ON con la referencia de tabla adyacente. Un desarrollador es libre de escribir un desastre como éste

SELECT 
    C.FullName, 
    C.CustomerCode, 
    O.OrderDate, 
    O.OrderTotal, 
    OD.ExtendedShippingNotes 
FROM 
    Customer C 
    CROSS JOIN Order O 
    INNER JOIN OrderDetail OD 
     ON C.CustomerID = O.CustomerID 
     AND C.CustomerStatus = 'Preferred' 
     AND O.OrderTotal > 1000.0 
WHERE 
    O.OrderID = OD.OrderID; 

Hablando de herramientas de consulta que "generarán ANSI-92", que estoy comentando aquí porque generó

SELECT 1 
    FROM DEPARTMENTS C 
     JOIN EMPLOYEES A 
      JOIN JOBS B 
    ON C.DEPARTMENT_ID = A.DEPARTMENT_ID 
    ON A.JOB_ID = B.JOB_ID 

La única sintaxis que se escapa El producto convencional "restring-project-cartesian product" es una combinación externa. Esta operación es más complicada porque no es asociativa (tanto consigo misma como con la unión normal). Uno tiene que hacer una consulta entre paréntesis juiciosa con la combinación externa, al menos. Sin embargo, es una operación exótica; si lo usa con demasiada frecuencia, le sugiero que tome una clase de base de datos relacional.

+3

Creo que su segundo ejemplo no es una sintaxis válida. –

+2

No veo cómo una unión externa es una operación "exótica". –

1

En mi opinión, la cláusula FROM es donde decido qué columnas necesito en las filas para que funcione mi cláusula SELECT. Es donde se expresa una regla de negocio que traerá a la misma fila, los valores necesarios en los cálculos. La regla comercial puede ser clientes que tienen facturas, lo que genera filas de facturas, incluido el cliente responsable. También podría ser lugares en el mismo código postal que los clientes, lo que da como resultado una lista de lugares y clientes cercanos.

Es donde trabajo con la centricidad de las filas en mi conjunto de resultados. Después de todo, simplemente nos muestran la metáfora de una lista en RDBMS, cada lista tiene un tema (la entidad) y cada fila es una instancia de la entidad. Si se entiende la centricidad de fila, se entiende la entidad del conjunto de resultados.

La cláusula WHERE, que se ejecuta conceptualmente después de definirse las filas en la cláusula from, elimina filas innecesarias (o incluye filas necesarias) para que la cláusula SELECT trabaje.

Como la lógica de unión puede expresarse tanto en la cláusula FROM como en la cláusula WHERE, y porque existen cláusulas para dividir y conquistar lógica compleja, elijo poner lógica de unión que implique valores en columnas en la cláusula FROM porque esencialmente expresando una regla comercial que es respaldada por valores coincidentes en columnas.

i.e.no voy a escribir una cláusula WHERE como esto:

WHERE Column1 = Column2 

I pondrá que en la cláusula FROM como esto:

ON Column1 = Column2 

Del mismo modo, si una columna es para ser comparado con valores externos (valores que puede o no estar en una columna), como comparar un código postal con un código postal específico, lo pondré en la cláusula WHERE porque básicamente digo que solo quiero filas como esta.

es decir, no voy a escribir una cláusula FROM como esto:

ON PostCode = '1234' 

voy a poner eso en la cláusula WHERE de esta manera:

WHERE PostCode = '1234' 
+0

'ON Y PostCode = '1234'' puede ser útil en' left joins' para la unión condicional, pero no excluye las filas con PostCode <>' 1234 ' – bummi

2

OK, ejecutan la misma. Eso está de acuerdo. A diferencia de muchos uso la convención anterior. Que SQL-92 es "más fácil de entender" es discutible. Habiendo escrito los lenguajes de programación durante 40 años (trago) sé que 'fácil de leer' comienza primero, antes que cualquier otra convención, con 'agudeza visual' (término mal aplicado aquí pero es la mejor frase que puedo usar). Al leer SQL lo primero que le importa es qué tablas están involucradas y qué tabla (la mayoría) define el grano. Luego, le importan las restricciones relevantes sobre los datos, luego los atributos seleccionados. Si bien SQL-92 generalmente separa estas ideas, hay tantas palabras ruidosas, que el ojo de la mente tiene que interpretarlas y lidiar con ellas, lo que hace que leer el SQL sea más lento.

SELECT Mgt.attrib_a AS attrib_a 
     ,Sta.attrib_b AS attrib_b 
     ,Stb.attrib_c AS attrib_c 
FROM Main_Grain_Table Mgt 
     ,Surrounding_TabA Sta 
     ,Surrounding_tabB Stb 
WHERE Mgt.sta_join_col = Sta.sta_join_col 
AND Mgt.stb_join_col = Stb.stb_join_col 
AND Mgt.bus_logic_col = 'TIGHT' 

Visual Acuity! poner las comas para los nuevos atributos delante Hace que comentar código más fácil también Utilice un caso específico de funciones y palabras clave Utilice un caso específico para las tablas Utilice un caso específico de atributos verticalmente Line hasta los operadores y las operaciones Hacer la primera tabla (s) en el FROM representan el grano de los datos Haga que las primeras tablas del WHERE sean restricciones de unión y permita que las restricciones específicas y ajustadas floten hacia abajo. Seleccione un alias de 3 caracteres para TODAS las tablas en su base de datos y use el alias EN TODAS PARTES que haga referencia a la tabla. También debe usar ese alias como un prefijo para (muchos) índices en esa tabla. 6 de 1 1/2 docena de otra, ¿verdad? Tal vez. Pero incluso si está usando la convención ANSI-92 (como lo he hecho y en los casos continuará) utilice principios de agudeza visual, alineación vertical para que su ojo visual se desvíe a los lugares que desea ver y evite las cosas fácilmente (particularmente palabras ruidosas) no es necesario.