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

92

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 conjuntos de datos muy grandes, y si son lentas, su sitio web lo es. Se necesita mucho tiempo para sacar todos esos bits de información separados del disco y ponerlos todos juntos de nuevo.

fuente

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


fuente

Respuestas:

98

La escalabilidad se trata de pre-computar, distribuir o reducir el trabajo repetido a lo esencial para minimizar el uso de recursos por unidad de trabajo. Para escalar bien, no hace nada que no necesite en volumen, y las cosas que realmente hace, debe asegurarse de que se hagan de la manera más eficiente posible.

En ese contexto, por supuesto, unir dos fuentes de datos separadas es relativamente lento, al menos en comparación con no unirlas, porque es un trabajo que debe realizar en vivo en el punto donde el usuario lo solicita.

Pero recuerde que la alternativa ya no es tener dos datos separados en absoluto; tienes que poner los dos puntos de datos dispares en el mismo registro. No puede combinar dos datos diferentes sin una consecuencia en alguna parte, así que asegúrese de comprender la compensación.

La buena noticia es que las bases de datos relacionales modernas son buenas para las combinaciones. Realmente no debería pensar que las uniones son lentas con una buena base de datos bien utilizada. Hay varias formas fáciles de escalar para tomar uniones sin formato y hacerlas mucho más rápidas:

  • Únase con una clave sustituta (usuario automático / columna de identidad) en lugar de una clave 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 combinación precalculada o una desnormalización administrada )
  • Columnas calculadas. Puede usar esto para hacer hash o precalcular las columnas clave de una combinación, de modo que lo que sería una comparación complicada para una combinación ahora sea mucho más pequeña y potencialmente preindexada.
  • Particiones de tabla (ayuda con grandes conjuntos de datos al distribuir la carga a varios discos o al limitar lo que podría haber sido un escaneo de tabla a un escaneo de partición)
  • OLAP (calcula previamente los resultados de ciertos tipos de consultas / uniones. No es del todo cierto, pero puede pensar en esto como una desnormalización genérica )
  • Replicación, grupos de disponibilidad, trasvase de registros u otros mecanismos para permitir que varios servidores respondan consultas de lectura para la misma base de datos y, por lo tanto, escale la carga de trabajo entre varios servidores.
  • Uso de una capa de almacenamiento en caché como Redis para evitar volver a ejecutar consultas que necesitan uniones complejas.

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 para almacenar datos estructurados (podría hacerlo con construcciones de archivos planos como csv o xml). Algunas de las opciones que enumeré incluso le permitirán construir completamente su combinación con anticipación, por lo que los resultados ya están listos antes de emitir la consulta, como si hubiera desnormalizado los datos (ciertamente a costa de operaciones de escritura más lentas).

Si tiene una unión lenta, probablemente no esté usando su base de datos correctamente.

La desnormalización debe realizarse solo después de que estas otras técnicas hayan fallado. Y la única forma de juzgar verdaderamente el "fracaso" es establecer metas de desempeño significativas y medirlas en función de ellas. Si no ha medido, es demasiado pronto para pensar siquiera en la desnormalización.

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

Joel Coehoorn
fuente
14
Los índices probablemente deberían estar en la parte superior de la lista. Muchos desarrolladores ( tos ) parecen olvidarse de ellos cuando prueban en un pequeño conjunto de datos y luego ponen de rodillas la base de datos en producción. He visto consultas que se ejecutan en el orden de 100.000 veces más rápido simplemente agregando índices. Y esos son índices arbitrarios sin siquiera hacer ningún análisis de datos en profundidad para determinar la mejor combinación para la coincidencia de prefijos más a la izquierda.
Duncan
Creo que tengo el orden correcto; es solo que la mayoría de los desarrolladores ya hacen el primer elemento, por lo que los índices son el primer elemento en el que deberán realizar cambios.
Joel Coehoorn
En su tercer elemento, menciona "Vistas materializadas / indexadas". ¿Estás hablando de vistas SQL regulares o algo más?
slolife
Las vistas SQL regulares de @slolife son como ejecutar una consulta adicional en segundo plano sobre la marcha cuando usa una consulta que hace referencia a la vista. Pero también puede decirle al servidor sql que "materialice" algunas vistas. Cuando haga esto, el servidor sql mantendrá una copia adicional de los datos de la vista, al igual que una tabla normal, de modo que cuando haga referencia a la vista en una consulta, ya no tenga que ejecutar esta consulta en segundo plano porque los datos ya están allí. . También puede poner diferentes índices en la vista que la tabla de origen, para ayudarlo a ajustar aún más el rendimiento.
Joel Coehoorn
Gracias Joel. Tendré que investigar eso.
slolife
29

Las uniones pueden ser más lentas que evitarlas mediante la desnormalización, pero si se usan correctamente (unir columnas con índices apropiados, etc.) no son inherentemente lentas .

La desnormalización es una de las muchas técnicas de optimización que puede considerar si su esquema de base de datos bien diseñado presenta problemas de rendimiento.

Tendayi Mawushe
fuente
2
... excepto en MySQL, que parece tener problemas de rendimiento con un gran número de uniones, independientemente de cómo se vean sus índices. O al menos lo ha hecho en el pasado.
Powerlord
2
Tomando en cuenta, si hay problemas conocidos con el DBMS específico (y quizás incluso con la versión), entonces este consejo puede tener sentido, pero como consejo general, es bastante engañoso si está utilizando una base de datos relacional. Dicho esto, los mecanismos de almacenamiento no relacionales se están volviendo más populares. SimpleDB y CouchDB de Amazon ( couchdb.apache.org ) son ejemplos. Si le sirve mejor dejar atrás el modelo relacional, probablemente debería dejar los productos optimizados para atrás también y buscar otras herramientas.
Tendayi Mawushe
13

el artículo dice que son lentos en comparación con la ausencia de uniones. esto se puede lograr con la desnormalización. por lo que existe una compensación entre velocidad y normalización. no te olvides de la optimización prematura también :)

Andrey
fuente
Incluso esta no es una regla estricta, si se une a una tabla, mysql podría usar un índice para realizar esa unión; esa unión de índice podría eliminar muchas filas y otro índice para cualquier cláusula where en las tablas. Si no se une, mysql generalmente usará solo un índice (que podría no ser el más eficiente), sin importar cómo esté formada su cláusula where.
leeeroy
11

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

En el mundo académico aprendemos cosas como las diversas formas normales (1ª, 2ª, 3ª, Boyce-Codd, etc.), y aprendemos sobre diferentes tipos de claves (primaria, extranjera, alternativa, única, etc.) y cómo estas cosas encajan para diseñar una base de datos. Y aprendemos los rudimentos de SQL, además de manipular tanto la estructura como los datos (DDL y DML).

En el mundo empresarial, muchos de los constructos académicos resultan ser sustancialmente menos viables de lo que nos habían hecho creer. Un ejemplo perfecto es la noción de clave primaria. Académicamente, es ese atributo (o colección de atributos) el que identifica de forma única una fila en la tabla. Entonces, en muchos dominios de problemas, la clave primaria académica adecuada es una combinación de 3 o 4 atributos. Sin embargo, casi todo el mundo en el mundo empresarial moderno utiliza un número entero secuencial generado automáticamente como clave principal de una tabla. ¿Por qué? Dos razones. La primera es porque hace que el modelo sea mucho más limpio cuando está migrando FK por todo el lugar. La segunda, y más relacionada con esta pregunta, es que la recuperación de datos a través de combinaciones es más rápida y eficiente en un solo entero que en 4 columnas varchar (como ya lo mencionaron algunas personas).

Profundicemos un poco más ahora en dos subtipos específicos de bases de datos del mundo real. El primer tipo es una base de datos transaccional. Esta es la base de muchas aplicaciones de administración de contenido o comercio electrónico que impulsan los sitios modernos. Con una base de datos de transacciones, está optimizando en gran medida hacia el "rendimiento de transacciones". La mayoría de las aplicaciones comerciales o de contenido tienen que equilibrar el rendimiento de las consultas (de ciertas tablas) con el rendimiento de las inserciones (en otras tablas), aunque cada aplicación tendrá sus propios problemas específicos impulsados ​​por el negocio que resolver.

El segundo tipo de base de datos del mundo real es una base de datos 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 transacciones donde se generan los datos y están altamente optimizadas para la velocidad de carga masiva de datos (ETL) y el rendimiento de consultas con conjuntos de datos grandes o complejos.

En cada caso, el desarrollador o DBA debe equilibrar cuidadosamente tanto la funcionalidad como las curvas de rendimiento, y hay muchos trucos para mejorar el rendimiento en ambos lados de la ecuación. En Oracle, puede hacer lo que se llama un "plan de explicación" para que pueda ver específicamente cómo se analiza y ejecuta una consulta. Está buscando maximizar el uso adecuado de los índices de la base de datos. Un no-no realmente desagradable es poner una función en la cláusula where de una consulta. Siempre que haga eso, garantiza que Oracle no usará ningún índice en esa columna en particular y probablemente verá un escaneo de tabla completo o parcial en el plan de explicación. Ese es solo un ejemplo específico de cómo se podría escribir una consulta que termina siendo lenta y no tiene nada que ver con las combinaciones.

Y mientras hablamos de escaneos de tablas, obviamente impactan en la velocidad de consulta proporcionalmente al tamaño de la tabla. Un escaneo completo de la tabla de 100 filas ni siquiera se nota. Ejecute la misma consulta en una tabla con 100 millones de filas y deberá volver la semana que viene para obtener la devolución.

Hablemos de normalización por un minuto. Este es otro tema académico en gran medida positivo que puede sobrecargarse. La mayoría de las veces, cuando hablamos de normalización, realmente nos referimos a la eliminación de datos duplicados colocándolos en su propia tabla y migrando un FK. La gente suele saltarse todo el asunto de la dependencia descrito por 2NF y 3NF. Y, sin embargo, en un caso extremo, ciertamente es posible tener una base de datos BCNF perfecta que es enorme y una bestia completa contra la que escribir código porque está muy normalizada.

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

Entonces, ¿por qué las uniones a veces son lentas? A veces es un mal diseño relacional. A veces es una indexación 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í obligado a proporcionar un contexto más sustancioso en torno a mis comentarios en lugar de simplemente recitar una respuesta de cuatro balas.

Ed Lucas
fuente
10

Las personas con bases de datos del tamaño de un terrabyte todavía usan combinaciones, si pueden hacer que funcionen en términos de rendimiento, usted también puede hacerlo.

Hay muchas razones para no denominar. Primero, la velocidad de las consultas seleccionadas no es la única ni siquiera la principal preocupación con las bases de datos. La integridad de los datos es la primera preocupación. Si desnormaliza, entonces debe implementar técnicas para mantener los datos desnormalizados a medida que cambian los datos principales. Entonces, suponga que desea almacenar el nombre del cliente en todas las tablas en lugar de unirse a la tabla del cliente en client_Id. Ahora, cuando cambia el nombre del cliente (100% de probabilidad de que algunos de los nombres de los clientes cambien con el tiempo), ahora necesita actualizar todos los registros secundarios para reflejar ese cambio. Si hace esto con una actualización en cascada y tiene un millón de registros secundarios, ¿qué tan rápido supone que será y cuántos usuarios sufrirán problemas de bloqueo y retrasos en su trabajo mientras sucede? Además, la mayoría de las personas que desnormalizan porque "

La desnormalización es un proceso complejo que requiere una comprensión profunda del rendimiento y la integridad de la base de datos para que se realice correctamente. No intente desnormalizar a menos que tenga dicha experiencia en el personal.

Las uniones son lo suficientemente rápidas si haces varias cosas. Primero use una clave suggorgate, una unión int es casi siempre la unión más rápida. En segundo lugar, indexe siempre la clave externa. Utilice tablas derivadas o condiciones de unión para crear un conjunto de datos más pequeño para filtrar. Si tiene una base de datos grande y compleja, contrate a una persona profesional en bases de datos con experiencia en particiones y administración de bases de datos enormes. Hay muchas técnicas para mejorar el rendimiento sin deshacerse de las uniones.

Si solo necesita la capacidad de consulta, entonces sí, puede diseñar un almacén de datos que se pueda desnormalizar y se rellene a través de una herramienta ETL (optimizada para la velocidad), no mediante la entrada de datos del usuario.

HLGEM
fuente
8

Las uniones son lentas si

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

Entonces, es cierto, cuanto más grandes sean sus conjuntos de datos, más procesamiento necesitará para una consulta, pero verificar y trabajar en las primeras tres opciones de lo anterior a menudo dará excelentes resultados.

Su fuente da la desnormalización como una opción. Esto está bien siempre y cuando haya agotado las mejores alternativas.

Paul Sasik
fuente
7

Las uniones pueden ser lentas si es necesario escanear grandes porciones de registros 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 registros de este último deben escanearse.

Para la lista de consultas esto, los optimizadores decentes probablemente ni siquiera considerarán la ruta de acceso al índice, haciendo una HASH JOINo una MERGE JOINen su lugar.

Tenga en cuenta que para una consulta como esta:

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

lo más probable es que la unión sea rápida: primero, customer_last_namese utilizará un índice para filtrar todos los Stellphlug (que, por supuesto, no son muy numerosos), luego account_customerse emitirá un escaneo de índice para cada Stellphlug para encontrar sus transacciones.

A pesar de que estos pueden ser miles de millones de registros en accountsy customers, solo unos pocos necesitarán ser escaneados.

Quassnoi
fuente
pero es difícil evitarlo. diseña tu aplicación para que este tipo de consultas no se ejecuten con demasiada frecuencia.
Andrey
1
Si se define un índice en la accounts(account_customer)mayoría de RDBMS, los RDBMS usarían ese índice para averiguar exactamente qué filas de la customersbase de datos deben escanearse.
jemfinch
sí, pero de todos modos no es una operación barata. puede almacenar la suma en algún campo y actualizar en cada transacción.
Andrey
@jemfinch: no, no lo harán. Esto requeriría escanear todo el índice solo para filtrar a los clientes, luego escanear el índice del cliente en un ciclo anidado. A HASH JOINsería mucho más rápido, por lo que es lo que se usará, excepto en todas las bases de datos principales MySQL, excepto , que solo hará que el customerslíder en un bucle anidado (ya que es más pequeño en tamaño)
Quassnoi
4

Joins are fast.Las uniones deben considerarse una práctica estándar con un esquema de base de datos normalizado correctamente. Las uniones le permiten unirse a grupos dispares de datos 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 optimización prematura, ya que la falla número uno de todos los proyectos de desarrollo es cumplir con la fecha límite. Una vez que haya completado el proyecto y comprenda las compensaciones, puede romper las reglas si puede justificarlo.

Es cierto que el rendimiento de la unión se degrada de forma no lineal a medida que aumenta el tamaño del conjunto de datos. Por lo tanto, no se escala tan bien como las consultas de tabla única, pero aún se escala.

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

Marcus Adams
fuente
3

Las uniones requieren un procesamiento adicional ya que tienen que buscar en más archivos y más índices para "unir" los datos. Sin embargo, "conjuntos de datos muy grandes" es relativo. ¿Cuál es la definición de grande? En el caso de JOIN, creo que es una referencia a un gran conjunto de resultados, no a ese conjunto de datos general.

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

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

No evite las JOIN, solo sepa que puede necesitar optimizar / desnormalizar cuando los conjuntos de datos se vuelven "muy grandes".

Brent Baisley
fuente
3

También del artículo que citó:

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

y

Y a menos que sea un sitio web realmente grande, probablemente no necesite preocuparse por este nivel de complejidad.

y

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

El artículo trata sobre mega sitios como Ebay. En ese nivel de uso, probablemente tendrá que considerar algo más que la simple administración de bases de datos relacionales. Pero en el curso "normal" del negocio (aplicaciones con miles de usuarios y millones de registros), esos enfoques más costosos y propensos a errores son excesivos.

Larry Lustig
fuente
2

Las uniones se consideran una fuerza opuesta a la escalabilidad porque normalmente son el cuello de botella y no se pueden distribuir o conectar fácilmente en paralelo.

Ben S
fuente
No estoy seguro de que esto sea cierto. Sé que Teradata ciertamente puede distribuir combinaciones entre Amps. Obviamente, ciertos tipos de combinaciones pueden ser más complicados / intratables que otros.
Cade Roux
los índices se pueden particionar en RDBMS que van desde mysql hasta oracle. AFAIK que escala (se distribuye y puede ser paralelo).
Unreason
2

Las tablas correctamente diseñadas que contienen los índices adecuados y las consultas escritas correctamente no siempre son lentas. Donde alguna vez escuchaste 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 unir muchas filas a la vez, puede recibir un golpe en comparación con una tabla desnormalizada, pero eso se remonta a las tablas diseñadas correctamente, sepa cuándo desnormalizar y cuándo no. en un sistema de informes pesado, divida los datos en tablas desnormalizadas para informes, o incluso cree un almacén de datos. En un sistema transaccional pesado, normalice las tablas.

KM.
fuente
1

La cantidad de datos temporales que se generan podría ser enorme en función de las combinaciones.

Por ejemplo, una base de datos aquí en el trabajo tenía una función de búsqueda genérica donde todos los campos eran opcionales. La rutina de búsqueda se unió a todas las mesas antes de que comenzara la búsqueda. Esto funcionó bien al principio. Pero, ahora que la tabla principal tiene más de 10 millones de filas ... no tanto. Las búsquedas ahora tardan 30 minutos o más.

Me encargaron optimizar el procedimiento almacenado de búsqueda.

Lo primero que hice fue que si se buscaba en alguno de los campos de la tabla principal, seleccioné una tabla temporal solo en esos campos. ENTONCES, me uní a todas las mesas con esa tabla temporal antes de hacer el resto de la búsqueda. Las búsquedas donde uno de los campos de la tabla principal ahora toman menos de 10 segundos.

Si no se comienza a buscar ninguno de los campos de la tabla principal, hago optimizaciones similares para otras tablas. Cuando terminé, ninguna búsqueda toma más de 30 segundos y la mayoría tiene menos de 10.

La utilización de la CPU del servidor SQL también disminuyó.

BoltBait
fuente
@BoltBait: ¿Es el mensaje para llevar que siempre debe intentar reducir el número de filas antes de realizar una unión?
unutbu
Ciertamente funcionó de maravilla en mi caso. Pero no optimizaría un sistema hasta que sea necesario.
BoltBait
normalmente no se generan datos temporales en las combinaciones (dependiendo, por supuesto, de la selectividad, la memoria disponible y el tamaño de los búferes de combinación), AFAIK; sin embargo, los datos temporales se crean normalmente por orden y se diferencian si no hay un índice que se pueda utilizar para tales operaciones.
Unreason
1

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

En una base de datos normalizada, una parte de los datos vivirá en un solo lugar, por lo que la huella para una actualización será la mínima posible. En una base de datos desnormalizada, es posible que la misma columna en varias filas o entre tablas deba actualizarse, lo que significa que la huella sería mayor y la posibilidad de bloqueos y puntos muertos puede aumentar.

Cade Roux
fuente
1

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 a partir de 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 en mi opinión, por lo que tienen (y merecen) respuestas excepcionales. El autor destaca específicamente la falta de IR y el grado de duplicación de datos en el artículo.

La mayoría de las aplicaciones, de nuevo, en mi opinión, se benefician de la validación y la reducción de la duplicación que proporcionan los RDBMS.

DaveE
fuente
0

Pueden ser lentos si se hacen de manera descuidada. Por ejemplo, si hace un 'seleccionar *' en una unión, probablemente tardará un poco en recuperar las 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.

Otávio Décio
fuente