¿Las uniones son para gente perezosa?

169

Recientemente tuve una discusión con otro desarrollador que me dijo que JOIN (SQL) no sirve para nada. Esto es técnicamente cierto, pero agregó que el uso de combinaciones es menos eficiente que realizar varias solicitudes y tablas de enlaces en el código (C # o Java).

Para él, las uniones son para gente perezosa a la que no le importa el rendimiento. ¿Es esto cierto? ¿Deberíamos evitar usar combinaciones?

Bastien Vandamme
fuente
114
No. Las bases de datos están optimizadas para realizar uniones, son extremadamente rápidas, especialmente para grandes conjuntos de datos. No desea que su aplicación cargue decenas de miles de filas y las combine manualmente.
halfdan
9191
Los lenguajes de programación son para gente perezosa; son menos eficientes que codificar manualmente las instrucciones de la CPU. :)
Michael McGowan
76
¿Cómo se llama el desarrollador? Quiero asegurarme de que nunca lo contrate.
Joe
39
@Michael meh, los programadores reales usan mariposas ...
Marc Gravell
14
Re su "esto es verdad" - no, no lo es. Las bases de datos funcionan a través de la teoría de conjuntos; se une a los sets funciona muy bien y de manera útil ...
Marc Gravell

Respuestas:

188

No, debemos evitar a los desarrolladores que tienen opiniones tan increíblemente erróneas.

En muchos casos, una unión de base de datos es varios órdenes de magnitud más rápido que cualquier cosa realizada a través del cliente, porque evita los viajes de ida y vuelta de la base de datos, y la base de datos puede usar índices para realizar la unión.

Fuera de mi cabeza, ni siquiera puedo imaginar un solo escenario en el que una combinación correctamente utilizada sea más lenta que la operación equivalente del lado del cliente.

Editar: Hay algunos casos raros en los que el código de cliente personalizado puede hacer las cosas de manera más eficiente que una unión directa a la base de datos (ver comentario de meriton). Pero esta es en gran medida la excepción.

Michael Borgwardt
fuente
1
¿Qué pasa con las uniones de 3 vías? ¿No hay casos en los que sería mejor hacerlo "en código"?
julien_c
56
Unirse en el servidor de aplicaciones puede ser más eficiente si unirse a la base de datos causa una redundancia severa en el conjunto de resultados enviado a través de la red. Considere las tablas A y B, donde cada fila en A está asociada con 20 filas en B, B tiene solo 100 filas, y queremos obtener las primeras 1000 filas de A con las filas asociadas de B. Unirse a la base de datos dará como resultado 20 * 1000 tuplas enviadas a través de la red. Si la unión se realiza en el servidor de la aplicación (primero recuperando toda la tabla B en la memoria), se envían solo 100 + 1000 filas a través de la red.
meriton
77
Sin embargo, es cierto que las uniones en la base de datos son mucho más rápidas en la mayoría de los casos y, por lo tanto, no son solo una cuestión de conveniencia, sino de necesidad.
meriton
13
He tenido la suerte de hablar con algunos de los desarrolladores que trabajan en SQL Server en Microsoft. Te hará marear escuchar las optimizaciones que hacen en las consultas. Cualquiera que piense que es más inteligente que eso debe ser golpeado.
riwalk
2
@meriton Estoy un poco sorprendido; Espero que la biblioteca del cliente optimice las uniones cruzadas.
Phil Lello
83

Me parece que a su colega le iría bien con una base de datos de documentos sin SQL o un almacén de valores clave. Que son en sí mismas muy buenas herramientas y una buena opción para muchos problemas.

Sin embargo, una base de datos relacional está muy optimizada para trabajar con conjuntos. Hay muchas, muchas formas de consultar los datos basados ​​en uniones que son ampliamente más eficientes que muchos viajes de ida y vuelta. De aquí proviene la versatilidad de un rdbms. También puede lograr lo mismo en una tienda nosql, pero a menudo termina creando una estructura separada adecuada para cada naturaleza diferente de la consulta.

En resumen: no estoy de acuerdo. En un RDBMS, las uniones son fundamentales . Si no los está utilizando, no lo está utilizando como RDBMS.

Marc Gravell
fuente
46

Bueno, él está equivocado en el caso general.

Las bases de datos pueden optimizar utilizando una variedad de métodos, ayudados por sugerencias de optimizadores, índices de tablas, relaciones de clave externa y posiblemente otra información específica del proveedor de la base de datos.

sehe
fuente
1
Tengo que admitir que cuando comencé a trabajar con bases de datos, creía que podía superar el rendimiento de las uniones. Pero no pasó mucho tiempo para darse cuenta de lo increíblemente rápido que es el DB. De hecho, diría que en esta situación es mejor discutirlo con el empleado de manera abierta en lugar de despedirlo como un idiota.
LegendLength
1
@LegendLength Diría que eso es cierto incluso si no son tan inteligentes. No es necesario asumir la inteligencia porque cometen los mismos errores que recordamos haber cometido (de hecho, para mí eso podría significar que no son tan inteligentes ...) Es más simple: rara vez ayuda ser despectivo. Está bien estar equivocado, de vez en cuando!
Sehe
24

No, no deberías.

Las bases de datos están específicamente diseñadas para manipular conjuntos de datos (obviamente ...). Por lo tanto, son increíblemente eficientes para hacer esto. Al hacer lo que es esencialmente una unión manual en su propio código, está tratando de asumir el papel de algo específicamente diseñado para el trabajo. Las posibilidades de que su código sea tan eficiente como en la base de datos son muy remotas.

Además, sin uniones, ¿cuál es el punto de usar una base de datos? también puede usar archivos de texto.

richzilla
fuente
2
Incluso sin unirse? Mapeo automático en memoria, almacenamiento en caché automático de consultas, muchas otras cosas automáticas que no ocurren en absoluto con la mayoría de los sistemas de archivos. Oh, ¿mencioné transacciones finamente controlables?
Piskvor salió del edificio el
19

Si "perezoso" se define como personas que quieren escribir menos código, entonces estoy de acuerdo. Si "perezoso" se define como personas que quieren tener herramientas para hacer lo que son buenos, estoy de acuerdo. Entonces, si simplemente está de acuerdo con Larry Wall (con respecto a los atributos de los buenos programadores), entonces estoy de acuerdo con él.

MJB
fuente
Agregué la precisión de perezoso: para las personas perezosas que no se preocupan por las actuaciones y prefieren escribir menos código. Creo que las uniones son para gente perezosa, pero en este caso las uniones también son mejores que varias solicitudes.
Bastien Vandamme
3
@Dran Dane: las uniones son para gente perezosa, sí. El hecho de que probablemente tengan un buen desempeño es ortogonal.
Piskvor salió del edificio el
16

Ummm, une es cómo las bases de datos relacionales relacionan las tablas entre sí. No estoy seguro de a qué se refiere.

¿Cómo puede ser más eficiente hacer varias llamadas a la base de datos que una llamada? Además, los motores sql están optimizados para hacer este tipo de cosas.

Quizás su compañero de trabajo sea demasiado vago para aprender SQL.

Giovanni Galbo
fuente
12

Si deberías.

Y debe usar C ++ en lugar de C # debido al rendimiento. C # es para gente perezosa.

No no no. Debe usar C en lugar de C ++ debido al rendimiento. C ++ es para gente perezosa.

No no no. Debe usar el ensamblaje en lugar de C debido al rendimiento. C es para gente perezosa.

Si, estoy bromeando. puede hacer programas más rápidos sin combinaciones y puede hacer programas utilizando menos memoria sin combinaciones. PERO en muchos casos, su tiempo de desarrollo es más importante que el tiempo de CPU y la memoria. Renunciar a un poco de rendimiento y disfrutar de tu vida. No pierdas tu tiempo con poco rendimiento. Y dile "¿Por qué no haces una carretera recta desde tu lugar hasta tu oficina?"

Dolor rojo
fuente
1
He visto todas tus respuestas hasta ahora y son muy divertidas. Por favor sigan viniendo. O eso o, ¿dónde puedo suscribirme a tu blog?
Gerry
11

"Esto es técnicamente cierto" - de manera similar, una base de datos SQL es inútil: ¿cuál es el punto de usar una cuando puedes obtener el mismo resultado al usar un montón de archivos CSV y correlacionarlos en el código? Diablos, cualquier abstracción es para gente perezosa, ¡volvamos a la programación en código máquina directamente en el hardware! ;)

Además, su afirmación es falsa en todos los casos, excepto en los más complicados: los RDBMS están muy optimizados para hacer que JOIN sea rápido . Sistemas de gestión de bases de datos relacionales , ¿verdad?

Piskvor salió del edificio
fuente
2
+1 La frase "... técnicamente verdadera" habría funcionado mejor si el OP hubiera usado la palabra en unnecessarylugar uselessde la oración anterior. Decir que las uniones son inútiles es evidentemente falso, sin tecnicismos que necesiten consideración. En cualquier caso, el malentendido de los OP y el colega sobre el punto de los RDBMS no es raro: stackoverflow.com/q/5575682/47550
Paul Sasik
7

La última compañía para la que trabajé tampoco usó uniones SQL. En cambio, trasladaron este trabajo a la capa de aplicación que está diseñada para escalar horizontalmente. La razón de este diseño es evitar el trabajo en la capa de base de datos. Suele ser la base de datos la que se convierte en cuello de botella. Es más fácil replicar la capa de aplicación que la base de datos. Podría haber otras razones. Pero este es el que puedo recordar ahora.

Sí, estoy de acuerdo en que las uniones realizadas en la capa de aplicación son ineficientes en comparación con las uniones realizadas por la base de datos. Más comunicación de red también.

Tenga en cuenta que no estoy tomando una posición firme para evitar las uniones SQL.

Srikanth
fuente
Bueno, eso suena como un argumento racional contra JOIN en su caso específico. Recuerdo que FB Engineering publicó algo similar en su blog: la ampliación también era su prioridad clave. Por desgracia, solo un pequeño porcentaje de programadores necesitará hacer esto, pero muchos piensan que lo hacen "porque OMG Facebook también lo hace";)
Piskvor dejó el edificio el
De acuerdo, en una solución empresarial en la que tenga suficiente tráfico para sobrecargar el servidor de la base de datos, puede valer la pena considerarlo, pero es más probable que sea el procedimiento almacenado de informes o la copia de seguridad programada que afecte el rendimiento. Las bases de datos son buenos en uniones, sobre todo si hay indecies a ayuda
Jodrell
@Jodrell: Sí, son buenos para unirse; De nuevo, hay casos en los que es necesario dejar caer la elegancia de las uniones para obtener más potencia. He conocido una de esas situaciones; probamos todas las soluciones posibles y, de hecho, una solución sin unión fue la más rápida en esa situación muy específica . Y no, no había nada más corriendo en ese servidor en particular; los procedimientos almacenados no pueden ralentizarlo si no tiene ninguno;)
Piskvor salió del edificio el
5

Sin combinaciones, ¿cómo va a relacionar los artículos de pedido con los pedidos? Ese es el objetivo de un sistema de gestión de bases de datos relacionales. Sin uniones no hay datos relacionales y también podría usar archivos de texto para procesar datos.

Parece que no entiende el concepto, así que está tratando de hacer que parezca que son inútiles. Es el mismo tipo de persona que cree que Excel es una aplicación de base de datos. Abofetearlo y decirle que lea más sobre bases de datos. Hacer múltiples conexiones y extraer datos y fusionar los datos a través de C # es la forma incorrecta de hacer las cosas.

JonH
fuente
5

No entiendo la lógica de la declaración "las uniones en SQL son inútiles". ¿Es útil filtrar y limitar los datos antes de trabajar en ellos? Como han dicho otros encuestados, esto es lo que hacen los motores de base de datos, debe ser en lo que son buenos.

Quizás un programador perezoso se apegaría a tecnologías con las que estaba familiarizado y evitaría otras posibilidades por razones no técnicas.

Te dejo a ti decidir.

Jodrell
fuente
5

Consideremos un ejemplo: una tabla con registros de facturas y una tabla relacionada con registros de líneas de pedido de facturas. Considere el pseudocódigo del cliente:

for each (invoice in invoices)
    let invoiceLines = FindLinesFor(invoice)
...

Si tiene 100,000 facturas con 10 líneas cada una, este código buscará 10 líneas de factura de una tabla de 1 millón, y lo hará 100,000 veces. A medida que aumenta el tamaño de la tabla, aumenta el número de operaciones de selección y aumenta el costo de cada operación de selección.

Debido a que las computadoras son rápidas, es posible que no note una diferencia de rendimiento entre los dos enfoques si tiene varios miles de registros o menos. Debido a que el aumento de costos es más que lineal, a medida que aumenta el número de registros (en millones, por ejemplo), comenzará a notar una diferencia, y la diferencia será menos tolerable a medida que crezca el tamaño del conjunto de datos.

La unión, sin embargo. utilizará los índices de la tabla y fusionará los dos conjuntos de datos. Esto significa que está escaneando efectivamente la segunda tabla una vez en lugar de accederla aleatoriamente N veces. Si hay una clave externa definida, la base de datos ya tiene los enlaces entre los registros relacionados almacenados internamente.

Imagina hacer esto tú mismo. Tiene una lista alfabética de estudiantes y un cuaderno con todos los informes de calificaciones de los estudiantes (una página por clase). El cuaderno está ordenado por los nombres de los alumnos, en el mismo orden que la lista. ¿Cómo preferirías continuar?

  1. Lee un nombre de la lista.
  2. Abre el cuaderno.
  3. Encuentra el nombre del alumno.
  4. Lea las calificaciones del alumno, pasando las páginas hasta llegar al siguiente alumno o la última página.
  5. Cierra el cuaderno.
  6. Repetir.

O:

  1. Abra el cuaderno en la primera página.
  2. Lee un nombre de la lista.
  3. Lea las notas para ese nombre del cuaderno.
  4. Repita los pasos 2-3 hasta llegar al final.
  5. Cierra el cuaderno.
phoog
fuente
5

Suena como un caso clásico de " Puedo escribirlo mejor ". En otras palabras, está viendo algo que ve como una especie de dolor en el cuello (escribir un montón de combinaciones en SQL) y dice "Estoy seguro de que puedo escribir eso mejor y obtener un mejor rendimiento". Debería preguntarle si es a) más inteligente yb) más educado que la persona típica que está metida de rodillas en el código de optimización de Oracle o SQL Server. Lo más probable es que no lo sea.

jcollum
fuente
3

Ciertamente está equivocado. Si bien hay ventajas definidas para la manipulación de datos dentro de lenguajes como C # o Java, las uniones son más rápidas en la base de datos debido a la naturaleza del propio SQL.

SQL sigue detallando estadísticas sobre los datos, y si ha creado sus índices correctamente, puede encontrar rápidamente un registro en un par de millones. Además del hecho de que ¿por qué querrías arrastrar todos tus datos a C # para hacer una unión cuando puedes hacerlo directamente en el nivel de la base de datos?

Las ventajas de usar C # entran en juego cuando necesitas hacer algo de forma iterativa. Si necesita hacer alguna función para cada fila, es probable que sea más rápido hacerlo dentro de C #, de lo contrario, la unión de datos se optimiza en la base de datos.

Mike M.
fuente
3

Diré que me he encontrado con un caso en el que fue más rápido romper la consulta y hacer las uniones en el código. Dicho esto, fue solo con una versión particular de MySQL que tuve que hacer eso. Todo lo demás, la base de datos probablemente será más rápida (tenga en cuenta que es posible que tenga que optimizar las consultas, pero aún así será más rápido).

JaCraig
fuente
3

Sospecho que tiene una visión limitada sobre para qué bases de datos deberían usarse. Un enfoque para maximizar el rendimiento es leer toda la base de datos en la memoria. En esta situación, puede obtener un mejor rendimiento y es posible que desee realizar uniones si la memoria es eficiente. Sin embargo, esto realmente no está utilizando una base de datos, como una base de datos en mi humilde opinión.

Peter Lawrey
fuente
3
La mayoría de los motores de bases de datos harán esto por usted detrás de escena de todos modos; y, por ejemplo, en MySQL puede crear una tabla puramente en memoria ( MEMORYmotor). Volver a implementar la funcionalidad de la base de datos sin la base de datos suele ser un signo de un caso grave de NIH;)
Piskvor abandonó el edificio el
@phoog: No inventado aquí , en otras palabras, "No pensé en eso, así que no existe". Muchas ruedas cuadradas se reinventaron debido a esto. (y sí, a veces reinventar la rueda es útil, por ejemplo, si estás haciendo autos de carrera; reinventar "solo porque" es poco probable que te consiga una mejor rueda)
Piskvor dejó el edificio el
En otras palabras, "No lo hice, así que debe ser basura". Esto tiene un grano de verdad solo en la medida en que "no lo he probado, por lo que podría no ser adecuado para mis propósitos", así que pruébelo antes de juzgarlo.
Peter Lawrey
@Piskvor: No necesariamente, la base de datos solo puede usar la memoria del sistema en el que se ejecuta, mientras que la aplicación puede usar la memoria del servidor de aplicaciones. Dicho de otra manera: si la base de datos está en un host dedicado, el acceso a ese caché aún requiere ancho de banda de red y está sujeto a la latencia de la red, pero cualquier caché que la aplicación mantenga puede consultarse con la velocidad de baja latencia del acceso a la memoria.
meriton
2

No, no solo las uniones están mejor optimizadas en el código de base de datos que ad-hoc C # / Java; pero generalmente se pueden aplicar varias técnicas de filtrado, lo que produce un rendimiento aún mejor.

Jonas Byström
fuente
2

Está equivocado, las uniones son lo que usan los programadores competentes. Puede haber algunos casos limitados en los que su método propuesto es más eficiente (y probablemente usaría una base de datos Documant), pero no puedo verlo si tiene una cantidad de datos difunta. Por ejemplo, tome esta consulta:

select t1.field1 
from table1 t1
join table2 t2 
    on t1.id = t2.id
where t1.field2 = 'test'

Suponga que tiene 10 millones de registros en la tabla 1 y 1 millón de registros en la tabla 2. Suponga que 9 millones de registros en la tabla 1 cumplen con la cláusula where. Suponga que solo 15 de ellos están en la tabla 2 también. Puede ejecutar esta instrucción sql que, si está indexada correctamente, tomará milisegundos y devolverá 15 registros a través de la red con solo 1 columna de datos. O puede enviar diez millones de registros con 2 columnas de datos y enviar por separado otros 1 millón de registros con una columna de datos a través de la red y combinarlos en el servidor web.

O, por supuesto, podría mantener todo el contenido de la base de datos en el servidor web en todo momento, lo cual es simplemente una tontería si tiene más que una cantidad trivial de datos y datos que cambian continuamente. Si no necesita las cualidades de una base de datos relacional, no use una. Pero si lo haces, úsalo correctamente.

HLGEM
fuente
2

He escuchado este argumento con bastante frecuencia durante mi carrera como desarrollador de software. Casi cada vez que se ha dicho, el tipo que hizo la afirmación no tenía mucho conocimiento sobre los sistemas de bases de datos relacionales, la forma en que funcionan y la forma en que dichos sistemas deberían usarse.

Sí, cuando se usa incorrectamente , las uniones parecen ser inútiles o incluso peligrosas. Pero cuando se usa de la manera correcta, existe un gran potencial para que la implementación de la base de datos realice optimizaciones y "ayude" al desarrollador a recuperar el resultado correcto de la manera más eficiente.

No olvide que el uso de un JOINle dice a la base de datos la forma en que espera que los datos se relacionen entre sí y, por lo tanto, le da a la base de datos más información sobre lo que está tratando de hacer y, por lo tanto, puede adaptarse mejor a sus necesidades.

Entonces la respuesta es definitivamente: ¡No, JOINSno son inútiles en absoluto!

perdian
fuente
0

Esto es "técnicamente cierto" solo en un caso que no se usa con frecuencia en las aplicaciones (cuando la consulta devuelve todas las filas de todas las tablas de las uniones). En la mayoría de las consultas, solo se devuelve una fracción de las filas de cada tabla. El motor de base de datos a menudo usa índices para eliminar las filas no deseadas, a veces incluso sin leer la fila real, ya que puede usar los valores almacenados en los índices. El motor de la base de datos está escrito en C, C ++, etc. y es al menos tan eficiente como el código escrito por un desarrollador.

fredt
fuente
0

A menos que haya entendido mal, la lógica de la pregunta es muy defectuosa.

Si hay 20 filas en B para cada A, 1000 filas en A implican 20k filas en B. No puede haber solo 100 filas en B a menos que haya muchas tablas "AB" con 20k filas con el mapeo .

Por lo tanto, para obtener toda la información sobre qué 20 de las 100 filas B se asignan a cada fila A, también debe colocar la tabla AB. Entonces esto sería:

  • 3 conjuntos de resultados de 100, 1000 y 20k filas y un cliente ÚNETE
  • un solo conjunto de resultados A-AB-B UNIDO con 20k filas

Por lo tanto, "JOIN" en el cliente agrega cualquier valor cuando examina los datos. No es que no sea una mala idea. Si estaba recuperando un objeto de la base de datos, quizás tenga más sentido dividirlo en conjuntos de resultados separados. Para una llamada de tipo informe, la aplanaría en una casi siempre.

En cualquier caso, diría que casi no sirve para una unión cruzada de esta magnitud. Es un mal ejemplo.

Tienes que unirte a algún lugar, y en eso RDBMS es bueno. No me gustaría trabajar con ningún mono de código de cliente que piense que pueden hacerlo mejor.

Idea tardía:

Para unirse al cliente se requieren objetos persistentes como DataTables (en .net). Si tiene un conjunto de resultados aplanado, puede consumirse a través de algo más ligero como un DataReader. Volumen alto = gran cantidad de recursos del cliente utilizados para evitar una base de datos JOIN.

gbn
fuente