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

 

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

Preguntas similares