¿Por qué las uniones son malas cuando se considera la escalabilidad?

¿Por qué las uniones son malas o "lentas"? Sé que escuché esto más de una vez. Encontré esta cita

El problema es que las uniones son relativamente lentas, especialmente en sets de datos muy grandes, y si son lentos, su website es lento. Lleva mucho time separar todos esos bits de información del disco y volverlos a unir.

fuente

Siempre pensé que eran rápidos especialmente cuando buscaba un PK. ¿Por qué son 'lentos'?

Unirse a dos fonts de datos independientes es relativamente lento, al less en comparación con no join a ellos. Pero recuerde que la alternativa es no tener más datos separados en absoluto; tienes que poner los dos puntos de datos dispares en el mismo logging. No puede combinar dos datos diferentes sin que haya una consecuencia en alguna parte, así que asegúrese de entender la compensación.

La buena noticia es que las bases de datos relacionales modernas son buenas en las uniones. En realidad, no debería pensar en uniones tan lentas con una buena database. La database proporciona varias forms de tomar uniones crudas y hacerlas mucho más rápidas:

  • Únase a una key sustituta (columna autonoma / identidad) en lugar de a una key natural. Esto significa comparaciones más pequeñas (y por lo tanto más rápidas) durante la operación de unión
  • Índices
  • Vistas materializadas / indexadas (piense en esto como una unión precalculada o desregulación gestionada )
  • Columna calculada Puede usar esto para comprimir o precomprar las columnas key de una combinación, de modo que lo que sería una comparación complicada para una combinación ahora es mucho más pequeño y potencialmente preindexado.
  • Particiones de tabla (ayuda con grandes sets de datos al distribuir la carga en varios discos o limitar lo que podría haber sido un escaneo de tabla a un escaneo de partición)
  • OLAP (calcula previamente los resultados de ciertos types de consultas / uniones. No es del todo cierto, pero puede pensar en esto como desnormalización genérica )

Me atrevería a decir que la razón principal por la que existen las bases de datos relacionales es para permitirle hacer uniones de manera eficiente * . Ciertamente, no es solo almacenar datos estructurados (podría hacerlo con construcciones de files planos como csv o xml). Algunas de las opciones que enumeré incluso le permitirán build completamente su unión por adelantado, por lo que los resultados ya están hechos antes de emitir la consulta, como si hubiera desnormalizado los datos (a sabiendas a costa de operaciones de escritura más lentas).

Si tiene una unión lenta, probablemente no esté utilizando su database correctamente.

La des-normalización debe hacerse solo después de que estas otras técnicas hayan fallado. Y la única forma en que realmente se puede juzgar el "fracaso" es establecer metas de performance significativas y medir en contra de esas metas. Si no ha medido, es demasiado pronto para siquiera pensar en la desnormalización.

* Es decir, existen como entidades distintas de las simples collections de tablas. Una razón adicional para un rdbms real es el acceso concurrente seguro.

Las uniones pueden ser más lentas que evitarlas a través de la desnormalización, pero si se usan correctamente (uniéndose a columnas con índices apropiados, etc.), no son intrínsecamente lentas .

La des-normalización es una de las muchas técnicas de optimization que puede considerar si su esquema de database bien diseñado presenta problemas de performance.

el artículo dice que son lentos en comparación con la ausencia de combinaciones. esto se puede lograr con la desnormalización. entonces hay una compensación entre la velocidad y la normalización. no te olvides de la optimization prematura también 🙂

Las personas con bases de datos de tamaño terrabyte todavía usan combinaciones, si pueden hacer que funcionen en function del performance, entonces tú también.

Hay muchas razones para no denominar. En primer lugar, la velocidad de las consultas de selección no es la única o principal preocupación con las bases de datos. La integridad de los datos es la primera preocupación. Si se desnormaliza, debe implementar técnicas para mantener los datos desnormalizados a medida que cambian los datos principales. Supongamos que lleva a almacenar el nombre del cliente en todas las tablas en lugar de join a la tabla del cliente en el Id_Cliente. Ahora, cuando cambie el nombre del cliente (100% de probabilidad de que algunos de los nombres de los clientes cambien con el time), ahora necesita actualizar todos los loggings secundarios para reflejar ese cambio. Si hace esto, tendrá una actualización en cascada y tendrá un millón de loggings secundarios, ¿qué tan rápido cree que va a ser eso y cuántos usuarios van a sufrir problemas de locking y retrasos en su trabajo mientras ocurre? Además, la mayoría de las personas que se desnormalizan porque "las uniones son lentas" no conocen lo suficiente sobre las bases de datos como para asegurarse de que su integridad de datos esté protegida y, a menudo, terminan con bases de datos inutilizables porque la integridad es tan mala.

La desnormalización es un process complejo que requiere una comprensión profunda del performance y la integridad de la database si se debe hacer correctamente. No intente desnormalizar a less que tenga dicha experiencia en el personal.

Las uniones son bastante rápidas si haces varias cosas. Primero use una key suggorgate, una combinación int es casi la combinación más rápida. Segundo siempre indexe la key foránea. Use tablas derivadas o condiciones de unión para crear un set de datos más pequeño para filtrar. Si tiene una database grande y muy compleja, contrate a una persona profesional de database con experiencia en la partición y administración de enormes bases de datos. Hay muchas técnicas para mejorar el performance sin deshacerse de las uniones.

Si solo necesita capacidad de consulta, entonces sí puede diseñar un datawarehouse que puede desnormalizarse y rellenarse a través de una herramienta ETL (optimizada para la velocidad) y no la input de datos del usuario.

Las uniones son lentas si

  • los datos están incorrectamente indexados
  • resultados pobremente filtrados
  • join a la consulta mal escrita
  • sets de datos muy grandes y complejos

Por lo tanto, es cierto que cuanto más grandes sean sus datos, mayor será el procesamiento que necesitará para una consulta, pero verificar y trabajar en las tres primeras opciones de lo anterior a menudo arrojará excelentes resultados.

Tu fuente da desnormalización como una opción. Esto está bien solo mientras hayas agotado mejores alternativas.

En primer lugar, la razón de ser de una database relacional (razón de ser) es poder modelar las relaciones entre las entidades. Las uniones son simplemente los mecanismos por los que atravesamos esas relaciones. Ciertamente tienen un costo nominal, pero sin uniones, realmente no hay razón para tener una database relacional.

En el mundo académico aprendemos cosas como las diversas forms normales (1º, 2º, 3º, Boyce-Codd, etc.), y aprendemos sobre diferentes types de keys (primaria, extranjera, alternativa, única, etc.) y cómo estas cosas encajan juntas para diseñar una database. Y aprendemos los rudimentos de SQL así como también manipulamos tanto la estructura como los datos (DDL y DML).

En el mundo corporativo, muchos de los constructos académicos resultan ser sustancialmente less viables de lo que nos habían hecho creer. Un ejemplo perfecto es la noción de una key principal. Académicamente es ese atributo (o colección de attributes) que identifica de manera única una fila en la tabla. Entonces, en muchos dominios problemáticos, la key primaria académica apropiada es un compuesto de 3 o 4 attributes. Sin embargo, casi todos en el mundo corporativo moderno usan un integer secuencial autogenerado como la key principal de una tabla. ¿Por qué? Dos razones. La primera es porque hace que el model sea mucho más limpio cuando estás migrando FK por todo el lugar. La segunda, y más pertinente a esta pregunta, es que la recuperación de datos a través de combinaciones es más rápida y más eficiente en un único integer que en 4 columnas varchar (como ya se mencionó por algunas personas).

Vamos a cavar un poco más profundo ahora en dos subtypes específicos de bases de datos del mundo real. El primer tipo es una database transaccional. Esta es la base de muchas aplicaciones de comercio electrónico o administración de contenido que manejan sitios modernos. Con un DB de transacción, se está optimizando fuertemente hacia "performance de transactions". La mayoría de las aplicaciones de comercio o contenido tienen que equilibrar el performance de las consultas (de ciertas tablas) con el performance de las inserciones (en otras tablas), aunque cada aplicación tendrá sus propios problemas específicos de negocios para resolver.

El segundo tipo de database del mundo real es una database de informes. Estos se utilizan casi exclusivamente para agregar datos comerciales y generar informes comerciales significativos. Por lo general, tienen una forma diferente a las bases de datos de transactions donde se generan los datos y están altamente optimizados para la velocidad de carga de datos en masa (ETL) y el performance de consultas con sets de datos grandes o complejos.

En cada caso, el desarrollador o DBA necesita equilibrar cuidadosamente tanto la funcionalidad como las curvas de performance, y hay muchos trucos para mejorar el performance en ambos lados de la ecuación. En Oracle puede hacer lo que se denomina un "plan de explicación" para que pueda ver específicamente cómo se analiza y se ejecuta una consulta. Está buscando maximizar el uso correcto de los índices por parte de la DB. Un desagradable realmente desagradable es poner una function en la cláusula where de una consulta. Cada vez que hace eso, garantiza que Oracle no usará ningún índice en esa columna en particular y es probable que vea un escaneo de tabla completo o parcial en el plan de explicación. Es solo un ejemplo específico de cómo se puede escribir una consulta que termina siendo lenta y no tiene nada que ver con las uniones.

Y aunque estamos hablando de escaneos de tabla, obviamente impactan la velocidad de consulta proporcionalmente al tamaño de la tabla. Una exploración de tabla completa de 100 filas ni siquiera se nota. Ejecute la misma consulta en una tabla con 100 millones de filas, y deberá regresar la próxima semana para la devolución.

Hablemos de normalización por un minuto. Este es otro tema académico en gran medida positivo que puede sobreestresarse. La mayoría de las veces, cuando hablamos de normalización, realmente nos referimos a la eliminación de datos duplicates poniéndolo en su propia tabla y migrando un FK. La gente generalmente omite toda la dependencia descrita por 2NF y 3NF. Y, sin embargo, en un caso extremo, sin duda es posible tener una database BCNF perfecta que es enorme y una bestia completa para escribir código en contra porque está tan normalizado.

Entonces, ¿dónde equilibramos? No hay una mejor respuesta única. Todas las mejores respuestas tienden a ser un compromiso entre la facilidad de mantenimiento de la estructura, la facilidad de mantenimiento de los datos y la facilidad de creación / mantenimiento del código. En general, mientras less duplicación de datos, mejor.

Entonces, ¿por qué las uniones a veces son lentas? A veces es un mal layout relacional. A veces es una indexing ineficaz. A veces es un problema de volumen de datos. A veces es una consulta horriblemente escrita.

Perdón por una respuesta tan larga, pero me sentí obligada a proporcionar un context más sustancioso en torno a mis comentarios en lugar de limitarme a una respuesta de cuatro balas.

Las uniones pueden ser lentas si se deben escanear grandes porciones de loggings de cada lado.

Me gusta esto:

SELECT SUM(transaction) FROM customers JOIN accounts ON account_customer = customer_id 

Incluso si se define un índice en account_customer , todos los loggings de este último aún deben ser escaneados.

Para la list de consultas esto, los optimizadores decentes probablemente ni siquiera considerarán la ruta de acceso al índice, haciendo un HASH JOIN o un MERGE JOIN lugar.

Tenga en count que para una consulta como esta:

 SELECT SUM(transaction) FROM customers JOIN accounts ON account_customer = customer_id WHERE customer_last_name = 'Stellphlug' 

la unión probablemente sea rápida: primero, se usará un índice en customer_last_name para filtrar todos los Stellphlug (que, por supuesto, no son muy numerosos), luego se account_customer un índice de exploración en account_customer para cada Stellphlug para encontrar sus transactions.

A pesar del hecho de que estos pueden ser miles de millones de loggings en accounts y customers , solo muy pocos necesitarán ser escaneados.

Las uniones requieren un procesamiento adicional, ya que deben search en más files y más índices para "unir" los datos entre sí. Sin embargo, "sets de datos muy grandes" es todo relativo. ¿Cuál es la definición de grande? En el caso de JOINs, creo que es una reference a un gran set de resultados, no a ese set de datos en general.

La mayoría de las bases de datos pueden procesar rápidamente una consulta que selecciona 5 loggings de una tabla principal y une 5 loggings de una tabla relacionada para cada logging (suponiendo que los índices correctos estén en su lugar). Estas tablas pueden tener cientos de millones de loggings cada uno, o incluso miles de millones.

Una vez que su set de resultados comience a crecer, las cosas se ralentizarán. Usando el mismo ejemplo, si la tabla principal da como resultado 100K loggings, entonces habrá 500K loggings "unidos" que deben ser encontrados. Simplemente extrayendo esa gran cantidad de datos de la database con retrasos adicionales.

No evite las UNIONES, solo sepa que puede necesitar optimizar / desnormalizar cuando los sets de datos se vuelvan "muy grandes".

Las uniones se consideran una fuerza opuesta a la escalabilidad, ya que suelen ser el cuello de botella y no se pueden distribuir fácilmente o en paralelo.

Las tablas correctamente diseñadas que contienen las indicaciones correctas y las consultas escritas correctamente no siempre se ralentizan. Donde sea que oíste eso:

¿Por qué las uniones son malas o "lentas"?

no tiene idea de lo que están hablando! La mayoría de las uniones serán muy rápidas. Si tiene que join a muchas filas al mismo time, puede recibir un golpe en comparación con una tabla desnormalizada, pero eso se remonta a las tablas diseñadas correctamente, saber cuándo desnormalizar y cuándo no hacerlo. en un sistema pesado de informes, divida los datos en tablas desnormalizadas para informes, o incluso cree un depósito de datos. En un sistema pesado transaccional normalice las tablas.

Joins are fast. Las uniones deben considerarse una práctica estándar con un esquema de database correctamente normalizado. Las uniones le permiten unir grupos de datos dispares de una manera significativa. No temas la unión.

La advertencia es que debe comprender la normalización, la unión y el uso adecuado de los índices.

Tenga cuidado con la optimization prematura, ya que la falla número uno de todos los proyectos de desarrollo está cumpliendo con la date límite. Una vez que haya completado el proyecto y comprenda las compensaciones, puede romper las reglas si puede justificarlo.

Es cierto que el performance de combinación se degrada de forma no lineal a medida que aumenta el tamaño del set de datos. Por lo tanto, no se escala tan bien como las consultas de tabla única, pero todavía escala.

También es cierto que un pájaro vuela más rápido sin alas, pero solo hacia abajo.

También del artículo que citó:

Muchos sitios web a gran escala con miles de millones de loggings, petabytes de datos, muchos miles de usuarios simultáneos y millones de consultas al día están utilizando un esquema de fragmentación e incluso algunos defienden la desnormalización como la mejor estrategia para diseñar el nivel de datos.

y

Y a less que sea un website realmente grande, probablemente no tenga que preocuparse por este nivel de complejidad.

y

Es más propenso a errores que hacer que la database haga todo este trabajo, pero usted puede escalar más allá de lo que las bases de datos más altas pueden manejar.

El artículo está discutiendo mega-sitios como Ebay. En ese nivel de uso es probable que tenga que considerar algo más que la simple gestión de bases de datos relacionales de vanilla. Pero en el curso "normal" de los negocios (aplicaciones con miles de usuarios y millones de loggings), los enfoques más caros y propensos a errores son exagerados.

La cantidad de datos temporales que se generan podría ser enorme en function de las uniones.

Por ejemplo, una database aquí en el trabajo tenía una function de búsqueda genérica donde todos los campos eran opcionales. La rutina de búsqueda se unió en cada table antes de que comenzara la búsqueda. Esto funcionó bien al principio. Pero, ahora que la table principal tiene más de 10 millones de filas … no tanto. Las búsquedas ahora demoran 30 minutos o más.

Me asignaron la tarea de optimizar el procedimiento almacenado de búsqueda.

Lo primero que hice fue si se buscaba alguno de los campos de la tabla principal, seleccioné una tabla temporal en esos campos solamente. ENTONCES, uní todas las tablas con esa tabla temporal antes de hacer el rest de la búsqueda. Busca donde uno de los campos principales de la tabla ahora toma less de 10 segundos.

Si ninguno de los campos de la tabla principal se comienza a search, realizo optimizaciones similares para otras tablas. Cuando terminé, ninguna búsqueda lleva más de 30 segundos con la mayoría de los menores de 10.

La utilización de la CPU del server SQL también se networkingujo.

Si bien las uniones (presumiblemente debido a un layout normalizado) pueden ser más lentas para la recuperación de datos que una lectura de una sola tabla, una database desnormalizada puede ser lenta para las operaciones de creación / actualización de datos ya que la huella de la transacción global no será mínima.

En una database normalizada, una pieza de datos vivirá en un solo lugar, por lo que la huella de una actualización será lo más mínima posible. En una database desnormalizada, es posible que se deba actualizar la misma columna en varias filas o en varias tablas, lo que significa que la huella sería mayor y que las posibilidades de lockings y lockings pueden boost.

Bueno, sí, seleccionar filas de una tabla desnormalizada (asumiendo índices decentes para su consulta) podría ser más rápido que seleccionar filas construidas al unir varias tablas, particularmente si las uniones no tienen índices eficientes disponibles.

Los ejemplos citados en el artículo – Flickr y eBay – son casos excepcionales de la OMI, por lo que tienen (y merecen) respuestas excepcionales. El autor específicamente menciona la falta de RI y el scope de la duplicación de datos en el artículo.

La mayoría de las aplicaciones (de nuevo, IMO) se benefician de la validation y duplicación networkingucida proporcionada por los RDBMS.

Pueden ser lentos si se hace descuidadamente. Por ejemplo, si haces 'seleccionar *' en una unión, probablemente tardes un time en recuperar cosas. Sin embargo, si elige cuidadosamente qué columnas devolver de cada tabla, y con los índices adecuados en su lugar, no debería haber ningún problema.