¿Columna duplicada para consultas más rápidas?


30

El título no tiene mucho sentido, pero no podría pensar en un título mejor para este problema.

Tengo las siguientes tablas

Proyectos

  • carné de identidad
  • nombre

Clientes

  • carné de identidad
  • id_project
  • nombre

Pagos

  • carné de identidad
  • id_customer
  • fecha
  • suma

Cuando un usuario ingresa al sistema, tendrá acceso a cierto proyecto. Ahora, quiero enumerar todos los pagos para ese proyecto, y debería ser bastante fácil:

SELECT FROM payments where id_customer in (SELECT id from customers where id_project = 5)

Mi pregunta es: si no es mejor agregar una columna id_project a la tabla de pagos de esta manera, las consultas serán más fáciles y rápidas.


1
así que la consulta no es un problema para los RDBMS modernos (o mejor, use join).
garik

44
De acuerdo, obtenga un plan de consulta para subseleccionar vs unirse y ver cuál es mejor
Gaius

1
Creo que vale la pena mirar esta publicación SO , ya que @igor mencionó el uso de JOIN o IN
CoderHawk el

Respuestas:


52

Parece que estás preguntando si la desnormalización tiene sentido.

La desnormalización es el proceso de intentar optimizar el rendimiento de lectura de una base de datos agregando datos redundantes o agrupando datos. En algunos casos, la desnormalización ayuda a encubrir las ineficiencias inherentes al software de base de datos relacional. Una base de datos relacional normalizada impone una gran carga de acceso sobre el almacenamiento físico de datos, incluso si está bien ajustada para un alto rendimiento.

La respuesta siempre es "depende", así que aquí está mi regla general:

Si ...

  • la cantidad de datos no es grande
  • ya no estás haciendo un montón de uniones
  • y / o el rendimiento de la base de datos no es actualmente un cuello de botella

entonces manténgase normalizado . Sí, la desnormalización es más rápida, pero también significa que tiene datos redundantes en el sistema, datos que deben mantenerse y sincronizarse. Ya no hay "una fuente" para esos datos, sino múltiples fuentes que pueden desviarse. Esto es arriesgado con el tiempo, por lo que no debe hacerlo a menos que tenga muy buenas razones para hacerlo, respaldado por algunos puntos de referencia.

Solo me desnormalizaría cuando ...

  • la cantidad de datos es muy grande
  • las uniones son caras y tienes que hacer muchas de ellas para obtener incluso consultas triviales devueltas
  • el rendimiento de la base de datos es un cuello de botella y / o quieres ir lo más rápido posible

Las uniones son muy rápidas en el hardware moderno, pero nunca son gratuitas.


9

Sería mejor reescribir la consulta como:

SELECT payments.*
FROM   customers
JOIN   payments 
ON     payments.id_customer = customers.id
WHERE  customers.id_project = 5

Si bien esto parece menos conciso y un buen planificador de consultas verá lo que está tratando de hacer y ejecutará su subconsulta correlacionada como la combinación anterior, un mal planificador de consultas puede terminar haciendo un análisis de índice de payments.id_customer(suponiendo que tenga un índice relevante ) (o peor, escaneo de tablas) en lugar de hacer las cosas de la manera más eficiente. Incluso un buen planificador de consultas puede no ver la optimización si la disposición de esta consulta está envuelta en algo más complicado. Expresar la relación como una unión en lugar de una subconsulta puede hacer más diferencia que cambiar su estructura de datos.

Como dice Jeff, cualquier denormalización debe considerarse con cuidado: puede aumentar el rendimiento fácilmente, especialmente para algunos fines de informes, pero puede generar inconsistencias debido a errores en la lógica comercial de soporte.

Como nota al margen: Obviamente, no conozco su negocio, por lo que podría perderme algo, pero sus relaciones con la mesa me parecen extrañas. Implican que nunca puede tener más de un proyecto con el mismo cliente, lo que generalmente no es cierto en mi experiencia, al menos durante un largo período.

customer     project      payment
--------     --------     -------
                          pa_id
             pr_id    <-- payment
cu_id    <-- customer     

o si está menos normalizado (aunque dudo que sea necesario):

customer     project      payment
--------     --------     --------
                          pa_id
             pr_id    <-- payment
cu_id    <-- customer 
           `------------- customer    

Por supuesto, eso todavía descuenta la posibilidad de un proyecto conjunto con dos clientes ...


3
Primera regla de rendimiento: ¡nunca usar * en producción!
Brian Ballsun-Stanton

@Brian: punto muy válido. Y además de las posibles implicaciones de rendimiento que evitan * en cláusulas selectas, también se evitan problemas con el ordenamiento de columnas en vistas en vista en MSSQL si sys.depends se sale de control debido al uso de DROP VIEW+ en CREATE VIEWlugar de ALTER VIEW.
David Spillett

@Brian puse * para facilitar la escritura.
Gabriel Solomon

El proyecto se piensa más como una aplicación independiente con su dominio en y pertenece a diferentes clientes, por lo que un cliente no puede tener la misma cuenta en diferentes proyectos
Gabriel Solomon

4

En algunas bases de datos, tiene la posibilidad de crear "Vistas materializadas" en lugar de VIEWS complejas con una gran cantidad de datos, basadas en una consulta compleja. Esto puede usarse para evitar la desnormalización en un sistema de aplicación histórico desarrollado. Si decide usar " Vistas materializadas "debe tener una idea clara de los métodos de actualización y la cantidad de almacenamiento que utilizará la Vista materializada ...

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.