mejorar update

18/11/2003 - 23:11 por Tolo | Informe spam
hola, vereis tengo un update metido en un trigger bastante cañero, pero
resumiendo tengo algo como esto:

update T_lineasDocumento
set
Basei = Inserted.precio_unitario*inserted.unidades, --
PU*unidades
total = (Inserted.precio_unitario*inserted.unidades) +
f_impuesto(Inserted.precio_unitario*inserted.unidades) -- Basei + Impuesto
de la Basei
from T_lineasDocumento inner join inserted on
inserted.id_linea=T_lineasDocumento .id_linea

Claro, aquí para hacer referencia cada vez a la Basei tengo que escribir la
función, imaginaros estoen un caso real donde hay a parte de estos campos
los campos, Precio_unitario, Precio unitario neto, descuento unitario, total
descuento, descuento, baseineto, baseibruto, total, importe impuesto, ...

claro, se me hacen las funciones interminables, más que por tema rendimiento
(q también algo afectará supongo) me gustaria poder simplificarlo por tema
de legibilidad del código.

alguna idea.

gracias

PD: si ya se que puedo usar campos calculados, pero luego siempre q queira
una select debo estar volviendo a escribir la fórmula y gastando tiempo de
cpu (creo yo inutilmente, pues hoy en día lo barato es el espacio en disco y
lo caro la memoria y la cpu, aparte de caro limitado).

Gracias (2)

Preguntas similare

Leer las respuestas

#6 Javier Loria
19/11/2003 - 17:33 | Informe spam
Hola Susana:
Repuestas
Puede que tengas razon?


Antes de escribir el codigo sabia que tenia razon :) y es muy simple se
mide la velocidad de los Discos Duros en Milisegundos y la memoria en
nanosegundos, para que valga la pena grabar un dato tendria la operacion que
involucrar mas de 100 columnas.
no me convence de eso es que en cada nueva consulta..


Totalmente de acuerdo. Lo normal seria realizar esto con vistas (VIEWS),
que logran el mismo efecto. Mi argumento con los campos calculados es que
logras EXACTAMENTE el mismo efecto que con el trigger, pero con un 50% mas
de eficiencia en los SELECT's y con un 500% de velocidad en los UPDATES. Si
quieres usar vistas es mucho mejor, tienen la ventaja de hacer mas facil el
mantenimiento de la BD.
porqué dices desnormalizar


La segunda regla normal, exige que ningun atributo NO Llave (en este caso el
Sub-Total) sea determinado enteramente por la llave Primaria
(Orden-Producto). En este caso Sub-Total depende enteramente de
Precio/Cantidad/Descuento y rompe la segunda regla normal.

Mis Comentarios
= Los estadares de diseno de normalizacion de datos, te ayudan a eliminar
la informacion redundate y a organizar los datos para que sean mas faciles
de mantener y manejar. Adicionalmente dividen las tablas grandes en tablas
mas pequenas y manejables. Cuando no normalizas, generalmente terminas con
aplicaciones mas lentas, mas dificiles de manejar y con un monton de codigo
de mantenimiento.
Significa esto que no se puede desnormalizar: NO. La desnormalizacion es
un proceso que ocurre despues de la normalizacion con el objetivo de mejorar
el desempeno. Ninguno de los casos recientes que se han posteado en este
foro ganan desempeno dernormalizando, todos terminan peor de como empezaron
(mas lentos, con mas codigo, y mas propensos a errores).
Un caso practico de cuando usaria desnormalizacion. Inmagina que tienes
un BD con las siguientes Tablas: Vendedores, Clientes, Productos, Facturas,
DetalleFacturas, ReciboDinero, RecibosFacturas (Facturas canceladas en un
Recibo).
Es probable que para calcular comisiones debas usar todas estas tablas
(asumiendo que los productos tienen un diferente % de comision). Si lo haces
una o 2 veces al mes esta bien hacerlo en un vista porque aun cuando la
seccion de JOIN involucra 7 Tablas no es mayor problema porque se ejecuta
pocas veces. Pero si en los requerimientos exigen que los Vendedores tienen
acceso a calcular su propia comision, puedes predecir que este calculo se
hara 100 veces diarias cada uno!!!.
Si quieres desnormalizar y por ejemplo incluir en la tabla de Recibos
una columna Vendedor y un TotalComisionVendedor que se calcula en el Trigger
(hay otra alternativas), eso me parece bien ya que hay una mejora importante
en la velocidad ya que estas ahorrandote un sinnumero de lecturas de disco y
una cantidad importante de calculos.
Cuando un maestro de obras (en la construccion) ve a un Ingeniero romper
una regla de Ingeneria, puede creer que es facil hacerlo y probablemente
trate de practicar lo "aprendido" con resultados desastrosos. Lo que no sabe
es que el Ingeniero rompe las reglas solo en contadas excepciones y con un
conocimiento exacto de lo que esta haciendo y su impacto.
Sera por esto que los ingenieros en Construccion tienen mejor reputacion
profesional que los Ingenieros de Software?

Saludos,


Javier Loria
Costa Rica
Se aprecia la inclusion de DDL (CREATE, INSERTS, etc.)
que pueda ser copiado y pegado al Query Analizer.
La version de SQL y Service Pack tambien ayuda.


Susana escribio:
Hola,

ok, puedes tener razón, a mi lo que no me convence de eso es que en
cada nueva consulta, tendría q volver a definir esos campos
calculados, q en mi caso son bastantes y no precisamente basados en
una suma o resta.

Lo que si que no entiendo es porqué dices desnormalizar, o voy muy
equivocado o no hay ninguna froma normal que diga nada de esto ...

gracias por tu comentario, lo estudiaré a ver.

"Javier Loria" escribió en el mensaje
news:%
Hola Tolo:
Gracias por la PosData :)
Con gusto te ayudo con el Trigger, pero veamos si es cierto que
los campos calculados son mas lentos que las columnas fisicas. Este
codigo esta hecho muy rapido y a lo Copy Paste:
/* Crea un BD de Pruebas */
CREATE DATABASE TESTDESEMPENO
USE TESTDESEMPENO
GO
/* Crea Dos Tablas, iguales a la de Order Details */
/* de Northwind una ccon campos Calculados y*/
/* otra con Columnas */
CREATE TABLE DetalleOrdenes (
OrderID int NOT NULL ,
ProductID int NOT NULL ,
UnitPrice money NOT NULL CONSTRAINT DF_Order_Details_UnitPrice
DEFAULT (0), Quantity smallint NOT NULL CONSTRAINT
DF_Order_Details_Quantity DEFAULT (1),
Discount real NOT NULL CONSTRAINT DF_Order_Details_Discount DEFAULT
(0), CONSTRAINT PK_Order_Details PRIMARY KEY CLUSTERED
(
OrderID,
ProductID
),
TotalBruto AS UnitPrice*Quantity,
TotalDescuentado AS UnitPrice*Quantity*(Discount),
TotalNeto AS UnitPrice*Quantity*(1-Discount),
CONSTRAINT CK_Discount CHECK (Discount >= 0 and Discount <= 1),
CONSTRAINT CK_Quantity CHECK (Quantity > 0),
CONSTRAINT CK_UnitPrice CHECK (UnitPrice >= 0)
)
GO

CREATE TABLE DetalleOrdenes2 (
OrderID int NOT NULL ,
ProductID int NOT NULL ,
UnitPrice money NOT NULL CONSTRAINT DF_Order_Details_UnitPrice2
DEFAULT (0),
Quantity smallint NOT NULL CONSTRAINT DF_Order_Details_Quantity2
DEFAULT (1),
Discount real NOT NULL CONSTRAINT DF_Order_Details_Discount2
DEFAULT (0), CONSTRAINT PK_Order_Details2 PRIMARY KEY CLUSTERED
(
OrderID,
ProductID
),
TotalBruto money NOT NULL,
TotalDescuentado money NOT NULL,
TotalNeto money NOT NULL,
CONSTRAINT CK_Discount2 CHECK (Discount >= 0 and Discount <= 1),
CONSTRAINT CK_Quantity2 CHECK (Quantity > 0),
CONSTRAINT CK_UnitPrice2 CHECK (UnitPrice >= 0)
)
GO

/* Insertemos unos 20,000 filas en ambas Tablas*/
INSERT DetalleOrdenes
SELECT OrderID + Numero*11500, ProductID, UnitPrice, Quantity,
Discount FROM Northwind.dbo.[Order Details]
CROSS JOIN
(SELECT 0 AS Numero UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7 UNION ALL
SELECT 8 UNION ALL
SELECT 9 UNION ALL
SELECT 10 ) AS N


INSERT DetalleOrdenes2
SELECT OrderID + Numero*11500, ProductID, UnitPrice, Quantity,
Discount, UnitPrice*Quantity, UnitPrice*Quantity*(Discount),
UnitPrice*Quantity*(1-Discount)
FROM Northwind.dbo.[Order Details]
CROSS JOIN
(SELECT 0 AS Numero UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7 UNION ALL
SELECT 8 UNION ALL
SELECT 9 UNION ALL
SELECT 10 ) AS N

/* Limpia los Buffers del Cache */
DBCC DROPCLEANBUFFERS

/************************************/
/************** Pruebas **************/
/************************************/
/* Primera Prueba */
SELECT ProductID,TotalBruto, TotalDescuentado, TotalNeto
FROM DetalleOrdenes
WHERE ProductID9

SELECT ProductID,TotalBruto, TotalDescuentado, TotalNeto
FROM DetalleOrdenes2
WHERE ProductID9

/* Segunda Prueba */
SELECT SUM(TotalBruto), SUM(TotalDescuentado), SUM(TotalNeto)
FROM DetalleOrdenes

SELECT SUM(TotalBruto), SUM(TotalDescuentado), SUM(TotalNeto)
FROM DetalleOrdenes2

/* Tercer Prueba */
SELECT ProductID,TotalBruto, TotalDescuentado, TotalNeto
FROM DetalleOrdenes2
WHERE OrderID337

SELECT ProductID,TotalBruto, TotalDescuentado, TotalNeto
FROM DetalleOrdenes
WHERE OrderID337

/* Fin de Codigo */
Revisas los planes de Ejecucion de las consultas veras que las dos
primeras son un 50% mas lentas en el segundo caso que en el primero.
O sea es bastante mas rapido NORMALIZAR que DESNORMALIZAR.
La ultima tiene el mismo desempeno.
Las actualizaciones de datos deben ser de 4 a 10 veces mas
lentas. Es muy facil decir esto es mas rapido o mas lento, lo
dificil es probarlo. :)

Saludos,


Javier Loria
Costa Rica
Se aprecia la inclusion de DDL (CREATE, INSERTS, etc.)
que pueda ser copiado y pegado al Query Analizer.
La version de SQL y Service Pack tambien ayuda.


Tolo escribio:
hola, vereis tengo un update metido en un trigger bastante cañero,
pero resumiendo tengo algo como esto:

update T_lineasDocumento
set
Basei = Inserted.precio_unitario*inserted.unidades, --
PU*unidades
total = (Inserted.precio_unitario*inserted.unidades) +
f_impuesto(Inserted.precio_unitario*inserted.unidades) -- Basei +
Impuesto de la Basei
from T_lineasDocumento inner join inserted on
inserted.id_linea=T_lineasDocumento .id_linea

Claro, aquí para hacer referencia cada vez a la Basei tengo que
escribir la función, imaginaros estoen un caso real donde hay a
parte de estos campos los campos, Precio_unitario, Precio unitario
neto, descuento unitario, total descuento, descuento, baseineto,
baseibruto, total, importe impuesto, ...

claro, se me hacen las funciones interminables, más que por tema
rendimiento (q también algo afectará supongo) me gustaria poder
simplificarlo por tema de legibilidad del código.

alguna idea.

gracias

PD: si ya se que puedo usar campos calculados, pero luego siempre q
queira una select debo estar volviendo a escribir la fórmula y
gastando tiempo de cpu (creo yo inutilmente, pues hoy en día lo
barato es el espacio en disco y lo caro la memoria y la cpu, aparte
de caro limitado).

Gracias (2)
email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una pregunta AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida