serian eficiente estos triggers

04/01/2004 - 16:59 por Yovanny Rojas | Informe spam
Hola amigos de foro:
Quiero hacer una consulta sobre triggers con relacion a que tan lento
pondrian estos mi aplicación

Me refiero si la tabla detalles seria de miles de registros y lo acumulara
en en la tabla de acumulaciones que presento a continuación, seria eficiente
esto y se podria usar en muchas tablas mi aplicacion esta hecha en visual
basic 6

Gracias.




Creación de triggers con Sql-Server
15 de Agosto de 2001


Todo lo que viene a continuación es código fuente con un ejemplo de como
usar las tablas inserted y deleted en triggers para que en insercciones
masivas
de datos no solamente tengamos acceso al primer elemento insertado o borrado
sino a todos, además evita el uso de cursores que enlentecen siempre el
proceso.

Observad que no borro las tablas temporales #insertados y #eliminados
ya que por definición su alcance es local al procedimiento (trigger en este
caso).


Bien, al código
Si quereis probarlo es suficiente con copiar y pegar a partir del create
table.
A disfrutar.

Create table detalles (id int identity(1,1) not null primary key,
Descripcion varchar(80) not null,
Codigo int ,
Cantidad int,
Precio money)
go -- y otra para guardar los acumulados .
create table acumulados (Codigo int not null, Cantidad int, Totalprecio
money)
go


create trigger trg_Detalles on detalles
for insert,update,delete -- Actuaré se haga lo que se haga desde este
trigger
as
insertando
registro.

select

Select Codigo,Sum(Cantidad) Cantidad,Sum(cantidad*Precio) precio
into #insertados
From inserted
group by codigo


update acumulados
set Acumulados.cantidad= Acumulados.cantidad +insertados.cantidad ,
Acumulados.TotalPrecio = Acumulados.TotalPrecio + insertados.precio
from #insertados insertados inner join acumulados on acumulados.codigo
=insertados.codigo
acumulados
insert into acumulados
select
inserted.Codigo,Sum(inserted.Cantidad),sum(inserted.precio*inserted.cantidad
)
from inserted left outer join Acumulados on inserted.codigo acumulados.codigo
where acumulados.codigo is null
group by inserted.codigo


go


insert into detalles values ('Primer elemento',1,1,1500)
go
select * from acumulados


go
insert into detalles values ('10 Unidades del primer elemento',1,10,1500)
go
select * from acumulados

existente,
es correcta


insert into detalles values ('10 Unidades del segundo elemento',2,10,1500)
go

insert into detalles select descripcion,codigo,cantidad,precio from detalles
go
select * from acumulados
go




alter trigger trg_Detalles on detalles
for insert,update,delete -- Actuaré se haga lo que se haga desde este
trigger
as

insertando
registro.

select

Select Codigo,Sum(Cantidad) Cantidad,Sum(cantidad*Precio) precio
into #insertados
From inserted
group by codigo


update acumulados
set Acumulados.cantidad= Acumulados.cantidad +insertados.cantidad ,
Acumulados.TotalPrecio = Acumulados.TotalPrecio + insertados.precio
from #insertados insertados inner join acumulados on acumulados.codigo
=insertados.codigo

acumulados

insert into acumulados
select
inserted.Codigo,Sum(inserted.Cantidad),sum(inserted.precio*inserted.cantidad
)
from inserted left outer join Acumulados on inserted.codigo acumulados.codigo
where acumulados.codigo is null
group by inserted.codigo



Select Codigo,Sum(Cantidad) Cantidad,Sum(cantidad*Precio) precio
into #Eliminados
From Deleted
group by codigo


update acumulados
set Acumulados.cantidad= Acumulados.cantidad - eliminados.cantidad ,
Acumulados.TotalPrecio = Acumulados.TotalPrecio - eliminados.precio
from #Eliminados eliminados inner join acumulados on acumulados.codigo eliminados.codigo

existiesen
¿Nó?
go

delete from detalles where id=1
go
select * from acumulados
go

delete from detalles
go
select * from acumulados


insert into detalles values ('10 Unidades del primer elemento',1,10,1500)
insert into detalles values ('Otras 10 Unidades del primer
elemento',1,10,1500)
insert into detalles values ('10 Unidades del segundo elemento',2,10,1500)
go
select * from acumulados
go
update detalles set cantidad=cantidad*2 where codigo=1
go
select * from acumulados
go

update detalles set cantidad=0
go
select * from acumulados
go
delete from detalles
go
select * from acumulados
go

Preguntas similare

Leer las respuestas

#1 Adrian Garcia
05/01/2004 - 00:52 | Informe spam
En mi opinion personal lo que lograrias es lo siguiente:

a) Buena performance en las lecturas que necesiten el valor acumulado
b) Pesima perfomance en tus actualizaciones. Por cada fila que insertes
(seguramente la operacion mas abitual) en la tabla de detalle debera ademas
actualizar la fila correspondiente a la tabla de cabecera.

Creo que podrias tener una decente perfomance en las lecturas y una buena
perfomance en las inserciones si defines correctamente las claves primarias,
si por ejemplo, defines tu clave primaria de la tabla detalle incluyendo en
su primera columna al id de la columna de la cabecera, SQL Server definira
un indice agrupado (cluster) sobre la clave primaria, con lo cual, todas las
filas pertenecientes a un fila de cabecera estaran fisicamente contiguas
reduciendo al maximo la cantidad de lecturas de paginas necesarias para
obtener el total.

Saludos
Adrian D. Garcia
NDSoft


"Yovanny Rojas" wrote in message
news:
Hola amigos de foro:
Quiero hacer una consulta sobre triggers con relacion a que tan lento
pondrian estos mi aplicación

Me refiero si la tabla detalles seria de miles de registros y lo acumulara
en en la tabla de acumulaciones que presento a continuación, seria


eficiente
esto y se podria usar en muchas tablas mi aplicacion esta hecha en visual
basic 6

Gracias.




Creación de triggers con Sql-Server
15 de Agosto de 2001


Todo lo que viene a continuación es código fuente con un ejemplo de como
usar las tablas inserted y deleted en triggers para que en insercciones
masivas
de datos no solamente tengamos acceso al primer elemento insertado o


borrado
sino a todos, además evita el uso de cursores que enlentecen siempre el
proceso.

Observad que no borro las tablas temporales #insertados y #eliminados
ya que por definición su alcance es local al procedimiento (trigger en


este
caso).


Bien, al código
Si quereis probarlo es suficiente con copiar y pegar a partir del create
table.
A disfrutar.

Create table detalles (id int identity(1,1) not null primary key,
Descripcion varchar(80) not null,
Codigo int ,
Cantidad int,
Precio money)
go -- y otra para guardar los acumulados .
create table acumulados (Codigo int not null, Cantidad int, Totalprecio
money)
go


create trigger trg_Detalles on detalles
for insert,update,delete -- Actuaré se haga lo que se haga desde este
trigger
as
insertando
registro.

select

Select Codigo,Sum(Cantidad) Cantidad,Sum(cantidad*Precio) precio
into #insertados
From inserted
group by codigo


update acumulados
set Acumulados.cantidad= Acumulados.cantidad +insertados.cantidad ,
Acumulados.TotalPrecio = Acumulados.TotalPrecio + insertados.precio
from #insertados insertados inner join acumulados on acumulados.codigo
=insertados.codigo
acumulados
insert into acumulados
select



inserted.Codigo,Sum(inserted.Cantidad),sum(inserted.precio*inserted.cantidad
)
from inserted left outer join Acumulados on inserted.codigo > acumulados.codigo
where acumulados.codigo is null
group by inserted.codigo


go


insert into detalles values ('Primer elemento',1,1,1500)
go
select * from acumulados


go
insert into detalles values ('10 Unidades del primer elemento',1,10,1500)
go
select * from acumulados

existente,
es correcta


insert into detalles values ('10 Unidades del segundo elemento',2,10,1500)
go

insert into detalles select descripcion,codigo,cantidad,precio from


detalles
go
select * from acumulados
go




alter trigger trg_Detalles on detalles
for insert,update,delete -- Actuaré se haga lo que se haga desde este
trigger
as

insertando
registro.

select

Select Codigo,Sum(Cantidad) Cantidad,Sum(cantidad*Precio) precio
into #insertados
From inserted
group by codigo


update acumulados
set Acumulados.cantidad= Acumulados.cantidad +insertados.cantidad ,
Acumulados.TotalPrecio = Acumulados.TotalPrecio + insertados.precio
from #insertados insertados inner join acumulados on acumulados.codigo
=insertados.codigo

acumulados

insert into acumulados
select



inserted.Codigo,Sum(inserted.Cantidad),sum(inserted.precio*inserted.cantidad
)
from inserted left outer join Acumulados on inserted.codigo > acumulados.codigo
where acumulados.codigo is null
group by inserted.codigo



Select Codigo,Sum(Cantidad) Cantidad,Sum(cantidad*Precio) precio
into #Eliminados
From Deleted
group by codigo


update acumulados
set Acumulados.cantidad= Acumulados.cantidad - eliminados.cantidad ,
Acumulados.TotalPrecio = Acumulados.TotalPrecio - eliminados.precio
from #Eliminados eliminados inner join acumulados on acumulados.codigo > eliminados.codigo

existiesen
¿Nó?
go

delete from detalles where id=1
go
select * from acumulados
go

delete from detalles
go
select * from acumulados


insert into detalles values ('10 Unidades del primer elemento',1,10,1500)
insert into detalles values ('Otras 10 Unidades del primer
elemento',1,10,1500)
insert into detalles values ('10 Unidades del segundo elemento',2,10,1500)
go
select * from acumulados
go
update detalles set cantidad=cantidad*2 where codigo=1
go
select * from acumulados
go

update detalles set cantidad=0
go
select * from acumulados
go
delete from detalles
go
select * from acumulados
go




Respuesta Responder a este mensaje
#2 Adrian Garcia
05/01/2004 - 08:43 | Informe spam
Recordemos que esta solucion solamente funciona en la version SQL Server
2000 Enterprise y SQL Server Developer.

En mi opinion, el costo de mantener un indice cluster adicional generaria
una sobrecarga superior a la de la ejecucion de los triggers en algunos
casos, analicemos las opciones
:
a) Cuando se insertaria una fila cabecera se deberia agregar una entrada al
indice cluster que mantiene la vista, en ese punto en la solucion con
triggers no haria falta.

b) Cuando se insertaria, eliminaria una fila en el detalle tambien se
debería actualizar la fila (y consecuentemente la pagina) en donde se
encuentra la fila en la vista indexada, similar a la solucion con triggers a
nivel de costo

c) Es necesario espacio en la base de datos para el nuevo indice

d) En las lecturas de las cabecera con los totales tendria un rendimiento
similar a la solucion con triggers a menos que:
1) La cantidad de columnas que definimos en la vista sea menor que la
cantidad de columnas definidas en la vista. Si son iguales o mayor la
cantidad de filas que entrarian por pagina seria igual o inferior a la de la
tabla base, con lo cual una index scan tardaría los mismo
2) Definimos como clave del indice cluster de la vista columnas que no
son claves primarias y que son usadas frecuentemente como parametros de
busqueda, especialmente si se definen rangos (por ejemplo rango de fechas).

e) Cuando se modifica algun monto en la tabla detalle el rendimiento de esta
operacion es similar a la de la opcion con triggers.

Saludos

Adrian D. Garcia
NDSoft


"SqlRanger" wrote in message
news:
Yo creo que sería mucho mejor dejar a un lado los triggers e implementar los
acumulados mediante una vista indexada. Al final el efecto es el mismo que
el conseguido mediante una tabla de acumulados y triggers, pero es mucho más
sencillo y eficiente:

CREATE TABLE Detalles (
id int identity(1,1) not null primary key,
Descripcion varchar(80) not null,
Codigo int not null ,
Cantidad int not null,
Precio money not null
)

GO

CREATE VIEW Acumulados WITH SCHEMABINDING
AS
SELECT COUNT_BIG(*) As Detalles, Codigo, SUM(Cantidad) AS Cantidad,
SUM(Cantidad * Precio) As TotalPrecio
FROM dbo.Detalles
GROUP BY Codigo

GO

CREATE UNIQUE CLUSTERED INDEX IdxAcumulados ON Acumulados(Codigo)

GO



Saludos:

Jesús López
MVP Microsoft .NET

"No darás tropezón ni desatino que no te haga adelantar camino"


"Yovanny Rojas" escribió en el mensaje
news:
Hola amigos de foro:
Quiero hacer una consulta sobre triggers con relacion a que tan lento
pondrian estos mi aplicación

Me refiero si la tabla detalles seria de miles de registros y lo acumulara
en en la tabla de acumulaciones que presento a continuación, seria eficiente
esto y se podria usar en muchas tablas mi aplicacion esta hecha en visual
basic 6

Gracias.




Creación de triggers con Sql-Server
15 de Agosto de 2001


Todo lo que viene a continuación es código fuente con un ejemplo de como
usar las tablas inserted y deleted en triggers para que en insercciones
masivas
de datos no solamente tengamos acceso al primer elemento insertado o borrado
sino a todos, además evita el uso de cursores que enlentecen siempre el
proceso.

Observad que no borro las tablas temporales #insertados y #eliminados
ya que por definición su alcance es local al procedimiento (trigger en este
caso).


Bien, al código
Si quereis probarlo es suficiente con copiar y pegar a partir del create
table.
A disfrutar.

Create table detalles (id int identity(1,1) not null primary key,
Descripcion varchar(80) not null,
Codigo int ,
Cantidad int,
Precio money)
go -- y otra para guardar los acumulados .
create table acumulados (Codigo int not null, Cantidad int, Totalprecio
money)
go


create trigger trg_Detalles on detalles
for insert,update,delete -- Actuaré se haga lo que se haga desde este
trigger
as
insertando
registro.

select

Select Codigo,Sum(Cantidad) Cantidad,Sum(cantidad*Precio) precio
into #insertados
From inserted
group by codigo


update acumulados
set Acumulados.cantidad= Acumulados.cantidad +insertados.cantidad ,
Acumulados.TotalPrecio = Acumulados.TotalPrecio + insertados.precio
from #insertados insertados inner join acumulados on acumulados.codigo
=insertados.codigo
acumulados
insert into acumulados
select
inserted.Codigo,Sum(inserted.Cantidad),sum(inserted.precio*inserted.cantidad
)
from inserted left outer join Acumulados on inserted.codigo acumulados.codigo
where acumulados.codigo is null
group by inserted.codigo


go


insert into detalles values ('Primer elemento',1,1,1500)
go
select * from acumulados


go
insert into detalles values ('10 Unidades del primer elemento',1,10,1500)
go
select * from acumulados

existente,
es correcta


insert into detalles values ('10 Unidades del segundo elemento',2,10,1500)
go

insert into detalles select descripcion,codigo,cantidad,precio from detalles
go
select * from acumulados
go




alter trigger trg_Detalles on detalles
for insert,update,delete -- Actuaré se haga lo que se haga desde este
trigger
as

insertando
registro.

select

Select Codigo,Sum(Cantidad) Cantidad,Sum(cantidad*Precio) precio
into #insertados
From inserted
group by codigo


update acumulados
set Acumulados.cantidad= Acumulados.cantidad +insertados.cantidad ,
Acumulados.TotalPrecio = Acumulados.TotalPrecio + insertados.precio
from #insertados insertados inner join acumulados on acumulados.codigo
=insertados.codigo

acumulados

insert into acumulados
select
inserted.Codigo,Sum(inserted.Cantidad),sum(inserted.precio*inserted.cantidad
)
from inserted left outer join Acumulados on inserted.codigo acumulados.codigo
where acumulados.codigo is null
group by inserted.codigo



Select Codigo,Sum(Cantidad) Cantidad,Sum(cantidad*Precio) precio
into #Eliminados
From Deleted
group by codigo


update acumulados
set Acumulados.cantidad= Acumulados.cantidad - eliminados.cantidad ,
Acumulados.TotalPrecio = Acumulados.TotalPrecio - eliminados.precio
from #Eliminados eliminados inner join acumulados on acumulados.codigo eliminados.codigo

existiesen
¿Nó?
go

delete from detalles where id=1
go
select * from acumulados
go

delete from detalles
go
select * from acumulados


insert into detalles values ('10 Unidades del primer elemento',1,10,1500)
insert into detalles values ('Otras 10 Unidades del primer
elemento',1,10,1500)
insert into detalles values ('10 Unidades del segundo elemento',2,10,1500)
go
select * from acumulados
go
update detalles set cantidad=cantidad*2 where codigo=1
go
select * from acumulados
go

update detalles set cantidad=0
go
select * from acumulados
go
delete from detalles
go
select * from acumulados
go
Respuesta Responder a este mensaje
#3 Adrian Garcia
07/01/2004 - 05:19 | Informe spam
Coincido contigo de que hay que evitar utilizar triggers. Ademas del costo
de rendimiento que generan estan los costos de mantenimiento a lo largo de
la vida del sistema. He visto en muchas oportunidades como el conocimiento
de que existan triggers sobre una tabla determinada se pierda (los
desarrolladores cambian, no existe documentacion sobre los mismo, el
desarrollador se olvido por completo, etc, etc) y despues se generen efectos
colaterales imprevistos ante modificaciones que se realizan.

Ahora respecto al espacio que ocuparia una vista indexada es muy superior al
de agregar una columna en la tabla cabecera. Por ejemplo, tenemos una tabla
que ocupa, digamos, unas 100 paginas de 8 KB del motor. Si sobre esa misma
tabla materializo una vista indexada que incluya a las mismos campos mas un
campo de totales entonces en mi base de datos necesitare 100 paginas
adicionales mas el espacio necesario para la columna nueva por el indice
cluster que la vista indexada genera.

Saludos
Adrian
"Miguel Egea" wrote in message
news:%
Bueno, como el código objeto de crítica es mio, me permito opinar :-d

Este trigger tendrá la mitad de rendimiento (según mis pruebas con un motón
de datos) que cualquier vista indexada y admitirá menos paralelismo. Por lo
que en resumen estoy con Jesús, si se puede no hay que usar triggers.

En cuanto al espacio, datos son datos, si hay que almacenarlos ocuparan el
mismo espacio acumulados en vistas indexadas que en una tabla de acumulados.

Por otra parte mi trigger (que esta hecho a efectos educativos), controla
los bloqueos y la concurrencia solo en parte, una actualizacio´n masiva
podría provocar resultados 'inesperados' sin el correcto tratamiento de
bloqueos y transacciones. Si tiramos por la calle de enmedio y bloqueamos
mucho seguramente acabemos serializando las inserciones y eso si que sería
tremendo. Las vista indexadas no tienen problemas (para nosotros al menos)
en esa gestión.

En resumen, un trigger mejor si lo evitamos

En cuanto a las vistas indexadas...

Los comandos SET que hay que establecer antes, (podéis mirar los books on
line), tienen que estar establecidos igual en todos los sps que hagan
cualquier actualización sobre la base de datos. He visto bastante
frecuentemente que si los sp's se modifican con el administrador
corporativo, estos comandos set, no están establecidos como necesitan las
vistas (debe ser solo cuestión de configuracio´n, pero por defecto no están
bien.). Por lo que si se hace así nuestra aplicación puede dar unos errores
bastante curiosos sin que 'aparentemente' nada se haya modificado. Sobre
todo si alguien curioseando tus sps pulsa aceptar en lugar de cancelar.

Por todo lo demás me gustan mucho y dan muy buen rendimiento

En cuanto a mi trigger y el rendimiento.

El hecho de usar tablas temporales en lugar de subselects no deja de ser por
claridad en el código, en cualquier caso no creo que perjudiquen
sensiblemente el rendimiento. Podrían usarse variables de tipo tabla, pero
al final hacen lo mismo, es decir se guardan en tempdb


=Miguel Egea
http://www.portalsql.com
Microsoft SQL-SERVER MVP.
Brigada Anti-Cursores
Aviso de Seguridad
http://www.microsoft.com/spain/tech...9-USER.asp
==



"SqlRanger" escribió en el mensaje
news:
Adrián,

A partir del Service Pack 3, las vistas indexadas están disponibles en todas
las ediciones de SQL Server, incluída la MSDE.

En mi opinión las soluciones basadas en vistas indexadas tienen un coste
similar a las soluciones basadas en tabla adicional + triggers tanto en
procesamiento como en espacio. Sin embargo el código que tienen esos
triggers al crear y usar tablas temporales da la impresión de ser menos
eficiente que el procesamiento interno que hace SQL Server de la vista
indexada.

Además no sólo hay que considerar el espacio y el rendimiento, una solución
basada en vistas indexadas es mucho más sencilla y mantenible que la basada
en tabla adicional + triggers.



Saludos:

Jesús López
MVP Microsoft .NET

"No darás tropezón ni desatino que no te haga adelantar camino"
email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaRespuesta Tengo una respuesta
Search Busqueda sugerida