Cursor muy lento

03/05/2004 - 17:03 por Jorge Eldis | Informe spam
Hola a todos

He leido en ese mismo News que trate por todos los medios de no usar
Cursores pero en realidad no encontre otra forma de hacerlo y ademas camina
super lento.

La logica de lo que tengo que hacer o mejor dicho lo que he estado haciendo
es lo siguiente.

Tengo N registros de una Tabla X y un campo que se llama Precio la cual por
regla de negocio tengo que aplicarle el precio despues, o sea no en el
momento en que se registra la transaccion, y este precio esta en base a un
Campo Cantidad cantidad.

La seleccion de los registros esta basadas en numerod de bodega esto es una
locura pero asi esta y hay que seguir hasta que estructuren, de hecho hay
bodegas quetienen numeros parecidos ejemplo 272154 y 272

Asi que lo que hago es seleccionar de mayor a menos, pero eso no es lo
importante una vez que hago el SELECT el proceso de poner el precio es super
lento.

Seria que Todos los productos que empiecen con el numero XXXX los les pongan
un precio, Ej. 2 Dolares por la cantidad.

Para darles mas o menos unos parametros serian 179900 registros, toma como 4
horas en ponerles el precio a todos en una Maquina P4, 1.7GHZ, 512MB RAM.

Yo hice lo siguiente:


CREATE PROCEDURE Tasacion

@Codigo nvarchar(10),
@Tasa FLOAT

AS

DECLARE @IdPro INT
DECLARE @LenCod INT
DECLARE @Cantidad NVARCHAR(50)
DECLARE @TasaTmp FLOAT



SET @LenCod = (LEN(@Codigo))

DECLARE TasacionCursor CURSOR FAST_FORWARD FOR

SELECT Id_Pro, Cantidad FROM Productos WITH (NOLOCK) WHERE LEFT(Dst,
@LenCod) @Codigo AND FlagTasado = 0

OPEN TasacionCursor

FETCH NEXT FROM TasacionCursor INTO @IdPro, @Cantidad

WHILE @@FETCH_STATUS = 0
BEGIN


SET @TasaTmp = (@Cantidad * @Tasa)


UPDATE Producto SET Tasa = @TasaTmp, FlagTasado = 1
WHERE (Id_Pro = @IdPro)


FETCH NEXT FROM TasacionCursor INTO @IdPro, @Cantidad

END

CLOSE TasacionCursor
DEALLOCATE TasacionCursor

Preguntas similare

Leer las respuestas

#1 Javier Loria
03/05/2004 - 17:42 | Informe spam
Hola Jorge:
Puede que ser que no entendienda el problema, pero el codigo que
escribiste me parece que es lo mismo a:
=UPDATE Producto
SET Tasa= (Productos.Cantidad*@Tasa)
, FlagTasado=1
FROM Producto
JOIN Productos
ON Producto.Id_Pro=Productos.Id_Pro
WHERE LEFT(Productos.Dst, LEN(@Codigo))=@Codigo
AND Productos.FlagTasado=0
= Adicionalmente, mal sintoma el LEFT(DST, LEN(@Codigo)) ya que
probablemente es una columna que no cumple la primera regla normal ya que
probablmente DTS no es atomico. Esto produce un problema de desempeno ya que
te obliga a no usar el indice y ha hacer un SCAN TABLE sobre toda la tabla,
es posible que:
*****
WHERE Productos.Dst LIKE @Codigo+'%'
*****
Sea mas rapido. Una actualizacion de estas deberia tardar minutos o
incluso segundos. Si la BD esta bien normalizada y no tiene problemas de
bloqueos. Por ultimo considero locura utilizar un NOLOCK, para usarlo de
base en una actualizacion.

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.


Jorge Eldis escribio:
Hola a todos

He leido en ese mismo News que trate por todos los medios de no usar
Cursores pero en realidad no encontre otra forma de hacerlo y ademas
camina super lento.

La logica de lo que tengo que hacer o mejor dicho lo que he estado
haciendo es lo siguiente.

Tengo N registros de una Tabla X y un campo que se llama Precio la
cual por regla de negocio tengo que aplicarle el precio despues, o
sea no en el momento en que se registra la transaccion, y este precio
esta en base a un Campo Cantidad cantidad.

La seleccion de los registros esta basadas en numerod de bodega esto
es una locura pero asi esta y hay que seguir hasta que estructuren,
de hecho hay bodegas quetienen numeros parecidos ejemplo 272154 y 272

Asi que lo que hago es seleccionar de mayor a menos, pero eso no es lo
importante una vez que hago el SELECT el proceso de poner el precio
es super lento.

Seria que Todos los productos que empiecen con el numero XXXX los les
pongan un precio, Ej. 2 Dolares por la cantidad.

Para darles mas o menos unos parametros serian 179900 registros, toma
como 4 horas en ponerles el precio a todos en una Maquina P4, 1.7GHZ,
512MB RAM.

Yo hice lo siguiente:


CREATE PROCEDURE Tasacion

@Codigo nvarchar(10),
@Tasa FLOAT

AS

DECLARE @IdPro INT
DECLARE @LenCod INT
DECLARE @Cantidad NVARCHAR(50)
DECLARE @TasaTmp FLOAT



SET @LenCod = (LEN(@Codigo))

DECLARE TasacionCursor CURSOR FAST_FORWARD FOR

SELECT Id_Pro, Cantidad FROM Productos WITH (NOLOCK) WHERE LEFT(Dst,
@LenCod) > @Codigo AND FlagTasado = 0

OPEN TasacionCursor

FETCH NEXT FROM TasacionCursor INTO @IdPro, @Cantidad

WHILE @@FETCH_STATUS = 0
BEGIN


SET @TasaTmp = (@Cantidad * @Tasa)


UPDATE Producto SET Tasa = @TasaTmp, FlagTasado = 1
WHERE (Id_Pro = @IdPro)


FETCH NEXT FROM TasacionCursor INTO @IdPro, @Cantidad

END

CLOSE TasacionCursor
DEALLOCATE TasacionCursor

Respuesta Responder a este mensaje
#2 ulises
03/05/2004 - 17:44 | Informe spam
Los cursores son lentos, creo que lo tuyo se podria hacer
facilmente con un UPDATE con JOIN, algo como :

CREATE PROCEDURE Tasacion
(
@Codigo nvarchar(10),
@Tasa FLOAT
)
AS
UPDATE Producto
SET Producto.Tasa = Productos.cantidad * @Tasa,
FlagTasado = 1
FROM Producto INNER JOIN Productos
ON Producto.Id_pro = Productos.Id_pro
WHERE Dst = @Codigo AND FlagTasado = 0

Saludos,
Ulises

Hola a todos

He leido en ese mismo News que trate por todos los medios


de no usar
Cursores pero en realidad no encontre otra forma de


hacerlo y ademas camina
super lento.

La logica de lo que tengo que hacer o mejor dicho lo que


he estado haciendo
es lo siguiente.

Tengo N registros de una Tabla X y un campo que se llama


Precio la cual por
regla de negocio tengo que aplicarle el precio despues, o


sea no en el
momento en que se registra la transaccion, y este precio


esta en base a un
Campo Cantidad cantidad.

La seleccion de los registros esta basadas en numerod de


bodega esto es una
locura pero asi esta y hay que seguir hasta que


estructuren, de hecho hay
bodegas quetienen numeros parecidos ejemplo 272154 y 272

Asi que lo que hago es seleccionar de mayor a menos, pero


eso no es lo
importante una vez que hago el SELECT el proceso de poner


el precio es super
lento.

Seria que Todos los productos que empiecen con el numero


XXXX los les pongan
un precio, Ej. 2 Dolares por la cantidad.

Para darles mas o menos unos parametros serian 179900


registros, toma como 4
horas en ponerles el precio a todos en una Maquina P4,


1.7GHZ, 512MB RAM.

Yo hice lo siguiente:


CREATE PROCEDURE Tasacion

@Codigo nvarchar(10),
@Tasa FLOAT

AS

DECLARE @IdPro INT
DECLARE @LenCod INT
DECLARE @Cantidad NVARCHAR(50)
DECLARE @TasaTmp FLOAT



SET @LenCod = (LEN(@Codigo))

DECLARE TasacionCursor CURSOR FAST_FORWARD FOR

SELECT Id_Pro, Cantidad FROM Productos WITH (NOLOCK)


WHERE LEFT(Dst,
@LenCod) >@Codigo AND FlagTasado = 0

OPEN TasacionCursor

FETCH NEXT FROM TasacionCursor INTO @IdPro, @Cantidad

WHILE @@FETCH_STATUS = 0
BEGIN


SET @TasaTmp = (@Cantidad * @Tasa)


UPDATE Producto SET Tasa = @TasaTmp, FlagTasado = 1
WHERE (Id_Pro = @IdPro)


FETCH NEXT FROM TasacionCursor INTO @IdPro, @Cantidad

END

CLOSE TasacionCursor
DEALLOCATE TasacionCursor



.

Respuesta Responder a este mensaje
#3 Jorge Eldis
04/05/2004 - 01:24 | Informe spam
Gracias, efectivamente que me estaba ahogando en un baso de agua, y el
cursor es suuuper lento.

Efectivo solo demoro como 4 segundos.


"Jorge Eldis" wrote in message
news:
Hola a todos

He leido en ese mismo News que trate por todos los medios de no usar
Cursores pero en realidad no encontre otra forma de hacerlo y ademas


camina
super lento.

La logica de lo que tengo que hacer o mejor dicho lo que he estado


haciendo
es lo siguiente.

Tengo N registros de una Tabla X y un campo que se llama Precio la cual


por
regla de negocio tengo que aplicarle el precio despues, o sea no en el
momento en que se registra la transaccion, y este precio esta en base a un
Campo Cantidad cantidad.

La seleccion de los registros esta basadas en numerod de bodega esto es


una
locura pero asi esta y hay que seguir hasta que estructuren, de hecho hay
bodegas quetienen numeros parecidos ejemplo 272154 y 272

Asi que lo que hago es seleccionar de mayor a menos, pero eso no es lo
importante una vez que hago el SELECT el proceso de poner el precio es


super
lento.

Seria que Todos los productos que empiecen con el numero XXXX los les


pongan
un precio, Ej. 2 Dolares por la cantidad.

Para darles mas o menos unos parametros serian 179900 registros, toma como


4
horas en ponerles el precio a todos en una Maquina P4, 1.7GHZ, 512MB RAM.

Yo hice lo siguiente:


CREATE PROCEDURE Tasacion

@Codigo nvarchar(10),
@Tasa FLOAT

AS

DECLARE @IdPro INT
DECLARE @LenCod INT
DECLARE @Cantidad NVARCHAR(50)
DECLARE @TasaTmp FLOAT



SET @LenCod = (LEN(@Codigo))

DECLARE TasacionCursor CURSOR FAST_FORWARD FOR

SELECT Id_Pro, Cantidad FROM Productos WITH (NOLOCK) WHERE LEFT(Dst,
@LenCod) > @Codigo AND FlagTasado = 0

OPEN TasacionCursor

FETCH NEXT FROM TasacionCursor INTO @IdPro, @Cantidad

WHILE @@FETCH_STATUS = 0
BEGIN


SET @TasaTmp = (@Cantidad * @Tasa)


UPDATE Producto SET Tasa = @TasaTmp, FlagTasado = 1
WHERE (Id_Pro = @IdPro)


FETCH NEXT FROM TasacionCursor INTO @IdPro, @Cantidad

END

CLOSE TasacionCursor
DEALLOCATE TasacionCursor



Respuesta Responder a este mensaje
#4 Jorge Eldis
04/05/2004 - 01:26 | Informe spam
Gracias, con la olucion de ambos me fue perfecto, gracias por su tiempo.

Ahora me comentas que el LIKE es mas eficiente que el LEFT, yo pensaba que
no asi que me entere ahora. Gracias, use el (LEFT)

Saludos Jorge Eldis

"Javier Loria" wrote in message
news:
Hola Jorge:
Puede que ser que no entendienda el problema, pero el codigo que
escribiste me parece que es lo mismo a:
=> UPDATE Producto
SET Tasa= (Productos.Cantidad*@Tasa)
, FlagTasado=1
FROM Producto
JOIN Productos
ON Producto.Id_Pro=Productos.Id_Pro
WHERE LEFT(Productos.Dst, LEN(@Codigo))=@Codigo
AND Productos.FlagTasado=0
=> Adicionalmente, mal sintoma el LEFT(DST, LEN(@Codigo)) ya que
probablemente es una columna que no cumple la primera regla normal ya que
probablmente DTS no es atomico. Esto produce un problema de desempeno ya


que
te obliga a no usar el indice y ha hacer un SCAN TABLE sobre toda la


tabla,
es posible que:
*****
WHERE Productos.Dst LIKE @Codigo+'%'
*****
Sea mas rapido. Una actualizacion de estas deberia tardar minutos o
incluso segundos. Si la BD esta bien normalizada y no tiene problemas de
bloqueos. Por ultimo considero locura utilizar un NOLOCK, para usarlo de
base en una actualizacion.

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.


Jorge Eldis escribio:
> Hola a todos
>
> He leido en ese mismo News que trate por todos los medios de no usar
> Cursores pero en realidad no encontre otra forma de hacerlo y ademas
> camina super lento.
>
> La logica de lo que tengo que hacer o mejor dicho lo que he estado
> haciendo es lo siguiente.
>
> Tengo N registros de una Tabla X y un campo que se llama Precio la
> cual por regla de negocio tengo que aplicarle el precio despues, o
> sea no en el momento en que se registra la transaccion, y este precio
> esta en base a un Campo Cantidad cantidad.
>
> La seleccion de los registros esta basadas en numerod de bodega esto
> es una locura pero asi esta y hay que seguir hasta que estructuren,
> de hecho hay bodegas quetienen numeros parecidos ejemplo 272154 y 272
>
> Asi que lo que hago es seleccionar de mayor a menos, pero eso no es lo
> importante una vez que hago el SELECT el proceso de poner el precio
> es super lento.
>
> Seria que Todos los productos que empiecen con el numero XXXX los les
> pongan un precio, Ej. 2 Dolares por la cantidad.
>
> Para darles mas o menos unos parametros serian 179900 registros, toma
> como 4 horas en ponerles el precio a todos en una Maquina P4, 1.7GHZ,
> 512MB RAM.
>
> Yo hice lo siguiente:
>
>
> CREATE PROCEDURE Tasacion
>
> @Codigo nvarchar(10),
> @Tasa FLOAT
>
> AS
>
> DECLARE @IdPro INT
> DECLARE @LenCod INT
> DECLARE @Cantidad NVARCHAR(50)
> DECLARE @TasaTmp FLOAT
>
>
>
> SET @LenCod = (LEN(@Codigo))
>
> DECLARE TasacionCursor CURSOR FAST_FORWARD FOR
>
> SELECT Id_Pro, Cantidad FROM Productos WITH (NOLOCK) WHERE LEFT(Dst,
> @LenCod) > > @Codigo AND FlagTasado = 0
>
> OPEN TasacionCursor
>
> FETCH NEXT FROM TasacionCursor INTO @IdPro, @Cantidad
>
> WHILE @@FETCH_STATUS = 0
> BEGIN
>
>
> SET @TasaTmp = (@Cantidad * @Tasa)
>
>
> UPDATE Producto SET Tasa = @TasaTmp, FlagTasado = 1
> WHERE (Id_Pro = @IdPro)
>
>
> FETCH NEXT FROM TasacionCursor INTO @IdPro, @Cantidad
>
> END
>
> CLOSE TasacionCursor
> DEALLOCATE TasacionCursor
>


Respuesta Responder a este mensaje
#5 Javier Loria
04/05/2004 - 04:31 | Informe spam
Hola Jorge:
No es que sea el LEFT lento y el LIKE rapido, lo que ocurre es que al
usar LEFT(Productos.Dst, LEN(@Codigo)), estas aplicando funciones sobre la
columna, lo cual deja al servidor ciego porque no sabe la densidad de los
datos ni puede usar el indice, el LIKE debe ser mas rapido, porque si puede
usar el indice.
Me alegro que te sirviera,
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.
Jorge Eldis escribio:
Gracias, con la olucion de ambos me fue perfecto, gracias por su
tiempo.

Ahora me comentas que el LIKE es mas eficiente que el LEFT, yo
pensaba que no asi que me entere ahora. Gracias, use el (LEFT)

Saludos Jorge Eldis

"Javier Loria" wrote in message
news:
Hola Jorge:
Puede que ser que no entendienda el problema, pero el codigo que
escribiste me parece que es lo mismo a:
=>> UPDATE Producto
SET Tasa= (Productos.Cantidad*@Tasa)
, FlagTasado=1
FROM Producto
JOIN Productos
ON Producto.Id_Pro=Productos.Id_Pro
WHERE LEFT(Productos.Dst, LEN(@Codigo))=@Codigo
AND Productos.FlagTasado=0
=>> Adicionalmente, mal sintoma el LEFT(DST, LEN(@Codigo)) ya que
probablemente es una columna que no cumple la primera regla normal
ya que probablmente DTS no es atomico. Esto produce un problema de
desempeno ya que te obliga a no usar el indice y ha hacer un SCAN
TABLE sobre toda la tabla, es posible que:
*****
WHERE Productos.Dst LIKE @Codigo+'%'
*****
Sea mas rapido. Una actualizacion de estas deberia tardar
minutos o incluso segundos. Si la BD esta bien normalizada y no
tiene problemas de bloqueos. Por ultimo considero locura utilizar un
NOLOCK, para usarlo de base en una actualizacion.

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.


Jorge Eldis escribio:
Hola a todos

He leido en ese mismo News que trate por todos los medios de no usar
Cursores pero en realidad no encontre otra forma de hacerlo y ademas
camina super lento.

La logica de lo que tengo que hacer o mejor dicho lo que he estado
haciendo es lo siguiente.

Tengo N registros de una Tabla X y un campo que se llama Precio la
cual por regla de negocio tengo que aplicarle el precio despues, o
sea no en el momento en que se registra la transaccion, y este
precio esta en base a un Campo Cantidad cantidad.

La seleccion de los registros esta basadas en numerod de bodega esto
es una locura pero asi esta y hay que seguir hasta que estructuren,
de hecho hay bodegas quetienen numeros parecidos ejemplo 272154 y
272

Asi que lo que hago es seleccionar de mayor a menos, pero eso no es
lo importante una vez que hago el SELECT el proceso de poner el
precio
es super lento.

Seria que Todos los productos que empiecen con el numero XXXX los
les pongan un precio, Ej. 2 Dolares por la cantidad.

Para darles mas o menos unos parametros serian 179900 registros,
toma como 4 horas en ponerles el precio a todos en una Maquina P4,
1.7GHZ, 512MB RAM.

Yo hice lo siguiente:


CREATE PROCEDURE Tasacion

@Codigo nvarchar(10),
@Tasa FLOAT

AS

DECLARE @IdPro INT
DECLARE @LenCod INT
DECLARE @Cantidad NVARCHAR(50)
DECLARE @TasaTmp FLOAT



SET @LenCod = (LEN(@Codigo))

DECLARE TasacionCursor CURSOR FAST_FORWARD FOR

SELECT Id_Pro, Cantidad FROM Productos WITH (NOLOCK) WHERE LEFT(Dst,
@LenCod) >>> @Codigo AND FlagTasado = 0

OPEN TasacionCursor

FETCH NEXT FROM TasacionCursor INTO @IdPro, @Cantidad

WHILE @@FETCH_STATUS = 0
BEGIN


SET @TasaTmp = (@Cantidad * @Tasa)


UPDATE Producto SET Tasa = @TasaTmp, FlagTasado = 1
WHERE (Id_Pro = @IdPro)


FETCH NEXT FROM TasacionCursor INTO @IdPro, @Cantidad

END

CLOSE TasacionCursor
DEALLOCATE TasacionCursor

email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaRespuesta Tengo una respuesta
Search Busqueda sugerida