2010-02-02 11 views
7

Estoy tratando de anticipar un poco y evitar un poco de dolor extra si es posible.pregunta de diseño de mesa simple

He tenido este problema en aplicaciones pasadas y generalmente he optado por el enfoque más detallado pero me gustaría las opiniones de algunos otros.

Si tiene una tabla básica como la siguiente, ¿es prudente y/o más eficiente incluir un campo que incluya un cálculo a partir de la información que se puede encontrar en otras dos columnas? IE:

+-----+---------+------------+-------+--------+-------+ 
| id | room_id | bookdate | price | people | total | 
+-----+---------+------------+-------+--------+-------+ 
| 414 | 132  | 2010-03-01 | 14.55 | 2  | 29.10 | 
| 415 | 132  | 2010-03-02 | 14.55 | 2  | 29.10 | 
| 416 | 132  | 2010-03-03 | 14.55 | 2  | 29.10 | 
+-----+---------+------------+-------+--------+-------+ 

La información contenida en el último campo se pudo extraer el producto de las dos anteriores, por lo que es redundante e innecesaria. ¿Hay casos en los que todavía podría valer la pena tenerlo?

+0

Esto también es para un proyecto con Rieles ... y la columna de totales se puede sumar en rieles haciendo ... Table.sum ('total'), sin embargo, encontrar la SUMA del producto de dos campos no tendría tal método incorporado. ;-( – holden

Respuesta

6

Como regla general, no almaceno los valores que pueden calcularse (especialmente los que se pueden calcular fácilmente) sobre la marcha a menos que haya una p problema de rendimiento y necesito ahorrar algo de tiempo de procesamiento.

Esta es una compensación clásica entre rendimiento y almacenamiento. Recomendaría calcular el valor hasta que necesite un aumento de rendimiento.

4

¿Tal vez crear una tabla, que contiene todos los campos excepto el último, y luego crear una vista que contiene todos los campos y cuenta los últimos campos automáticamente?

Así que la mesa estaría constituido únicamente por estos campos

+-----+---------+------------+-------+--------+ 
| id | room_id | bookdate | price | people | 
+-----+---------+------------+-------+--------+ 
| 414 | 132  | 2010-03-01 | 14.55 | 2  | 

y la definición de la vista, que calcula el total es también muy simple:

select *, price*people as total from rooms 

(suponiendo que la tabla se llama rooms

0

Me gustaría continuar y poner en el campo TOTAL. Por lo que puedo ver aquí no hay 'DESCUENTO' o campo similar que pueda reducir el total, pero puedo imaginar escenarios en los que el precio * el número de personas podría no ser igual al total. Es posible que desee considerar un campo COMENTARIOS o incluso una tabla para permitir que alguien tenga en cuenta por qué el total no coincide con el producto de los otros campos.

Comparte y disfruta.

2

La regla general es que no debe almacenar lo que puede calcular fácilmente, pero si ha identificado esta área como un cuello de botella de rendimiento — perfilando su aplicación, no conjeturas —, hágalo.

0

Básicamente prefiero no tener un campo "total", o cualquier campo que sea calculado por otros campos, no en la misma tabla ni en otras tablas. Si el campo de precio cambia, alguien podría "olvidarse" de actualizar el campo total y terminará con datos incorrectos.

Es muy fácil SELECCIONAR usando este campo: SELECCIONAR precio, personas, (precio * personas) COMO total DE some_table;

El único caso que creo que es correcto mantener un campo calculado es cuando lleva mucho tiempo calcularlo y sobrecargará la base de datos en una gran cantidad de datos.

BR

0

En general se considera una mala práctica para almacenar los campos que se pueden calcular simplemente a partir de otros campos de la tabla. La única vez que lo recomendaría sería cuando necesita almacenar el resultado de un cálculo complejo y es más fácil almacenar el valor calculado que volver a calcular el valor cada vez; sin embargo, en su caso, esto no parece necesario.

El otro problema con los campos calculados es que los valores originales utilizados para el cálculo se pueden cambiar sin modificar el resultado almacenado, lo que puede causar problemas potenciales en la aplicación.

1

Si lo hace por comodidad al escribir consultas, crearía una vista que incluya el total en su lugar.

De lo contrario, esto es una cuestión de normalization. A veces, la desnormalización de una tabla es aceptable. Denormalization, especialmente en un entorno como un almacén de datos, se puede utilizar para aumentar el rendimiento. Sin embargo, es importante asegurarse de que sus datos se mantengan consistentes. En otras palabras, debe asegurarse de que su campo total se actualice cuando price o people cambien.

En la práctica, considero esto como un último recurso, solo para utilizarlo cuando otras optimizaciones de rendimiento se quedan cortas. Además, la desnormalización no garantiza una mejora: según la cantidad de datos y otros factores, en realidad podría empeorar las cosas.

Nota: una tabla no puede ser 3NF (tercera forma normal) hasta que se eliminen los campos calculados.

0

Como puede calcular el valor, con bastante facilidad en este caso, es redundante. Casi nunca debería almacenar datos redundantes. Esto significa que en todos los lugares donde actualice el precio o las personas, debe asegurarse de actualizar el total. Si olvida hacer esto en un solo lugar, los datos ahora son inconsistentes. Supongamos que ahora tiene un registro que dice precio = $ 10, personas = 3, total = $ 40. Si tiene diferentes programas que muestran información de diferentes maneras - diferentes totales o subconjuntos o lo que sea - el usuario podría obtener diferentes respuestas a la misma pregunta dependiendo de cómo lo haya solicitado. Si bien es malo obtener una respuesta incorrecta, es incluso peor que a veces obtener una respuesta correcta y, a veces, una respuesta incorrecta, porque entonces puede no estar claro cómo solucionar el problema. Quiero decir, si veo que cierto cliente muestra a 2 personas cuando debería mostrar 3, presumiblemente hay alguna pantalla a la que puedo acceder, sobreescriba el 2 con un 3, haga clic en guardar o lo que sea, y se soluciona. Pero si dice $ 10 por 2 personas = $ 30, ¿a dónde voy a arreglarlo? ¿Cómo?

Puede decir que el registro solo se actualiza en un solo lugar, por lo que no hay problema. Pero eso es hoy. ¿Qué pasa si mañana usted o algún otro programador agrega una nueva función para hacer un tipo diferente de actualización?

Estoy trabajando en un sistema ahora que está lleno de datos redundantes. La información básica sobre cada uno de los productos de nuestra compañía se almacena en una tabla de "artículos". Para cada unidad en existencia tenemos un registro de existencias, y en lugar de simplemente referirnos al registro del artículo, copian todos los datos de cada unidad de stock. Cuando se vende un artículo, copiamos todos los datos en el registro de venta. Si se devuelve algo, copiamos todos los datos en el registro de devolución. Etc, etc. para muchos otros tipos de registros. Esto causa problemas sin fin. Una vez tuvimos un problema en el que un usuario ejecutaba una consulta en busca de elementos con ciertas características y la lista de resultados incluía elementos que no cumplían los criterios de búsqueda. ¿Por qué? Porque la consulta encuentra todos los registros de elementos que cumplen los criterios de búsqueda, que intenta hacer coincidir los registros de elementos con los registros de stock por número de parte ... pero algunos de los registros de stock no coinciden con el registro de artículo en otros criterios por varias razones. En este momento estoy trabajando para solucionar un problema donde los datos de costos no siempre se copian de los registros de stock a los registros de venta de forma adecuada.Me encantaría rediseñar la base de datos para eliminar toda la información redundante, pero sería un gran proyecto.

Claro, hay momentos en que la penalización de rendimiento para recalcular algunos datos es demasiado alta. Por ejemplo, si necesita leer miles de registros de transacciones para calcular el saldo actual, y quiere mostrar regularmente el saldo actual, puede que sea una carga de rendimiento demasiado alta y será mejor que la almacene de forma redundante. Pero sería muy lento para hacer ese tipo de cosas. Asegúrese de que realmente sea un problema de rendimiento serio.

¿Multiplicar dos números juntos que están en un registro que ya está leyendo? De ninguna manera. No puedo imaginar que eso causaría problemas de rendimiento. Si su motor de base de datos no puede multiplicar dos números en un pequeño porcentaje del tiempo que lleva leer un registro, obtenga un nuevo motor de base de datos.

2

Si decide desnormalizar el rendimiento de lectura, puede agregar una restricción de verificación para aplicar consistencia.

create table rooms (
    price numeric, 
    people numeric, 
    total numeric check (total=price*people)); 

Esto agregará una sobrecarga ligera a las inserciones y actualizaciones.

1

Si le preocupa el rendimiento selectivo (al menos con un WHERE total = xx.xx), puede agregar un índice.

CREAR ÍNDICE booking_total ON reserva ((precio * personas));

Eso cambiará el plan de consulta para SELECT * from booking where price*people = 58.2; de esto;

Seq Scan on booking (cost=0.00..299.96 rows=60 width=24) (actual time=0.015..2.926 rows=1 loops=1) Filter: ((price * (people)::double precision) = 58.2::double precision) Total runtime: 2.947 ms

a esta

Bitmap Heap Scan on booking (cost=4.30..20.83 rows=5 width=24) (actual time=0.016..0.016 rows=1 loops=1) Recheck Cond: ((price * (people)::double precision) = 58.2::double precision) -> Bitmap Index Scan on booking_total (cost=0.00..4.29 rows=5 width=0) (actual time=0.009..0.009 rows=1 loops=1) Index Cond: ((price * (people)::double precision) = 58.2::double precision) Total runtime: 0.044 ms

rocas PostgreSQL :-)

2

estoy a menudo en favor de un campo calculado suponiendo que lo hace correctamente mediante la definición de campo en base de datos calculada. De esta forma, el cálculo siempre es aplicable independientemente de cómo cambien los datos. Sin embargo, solo haría esto si necesitas obtener esos cálculos en informes que contienen muchos registros. Claro que es fácil escribir la fórmula en la consulta, pero si calcula este número con frecuencia está desperdiciando recursos del servidor (un campo calculado solo calcula cuando la información cambia) y posiblemente ralentizando seriamente la consulta si debe hacer el cálculo para millones de registros para informes. Una vista materializada también es una buena idea (porque precalculará), pero una vista regular simplemente lo saca de escribir el cálculo varias veces, no tiene el beneficio de rendimiento de un campo calculado. Por otro lado, nunca creo vistas si no las necesito (es decir, puedo resolver el problema de otra manera), ya que pueden generar problemas de rendimiento reales cuando las personas comienzan a crear vistas sobre las vistas. No use un martillo cuando un destornillador es lo que necesita.

Los campos calculados son herramientas potentes cuando se usan correctamente y los diseñadores de bases de datos a menudo los pasan por alto.