En este artículo se muestra como cambiar el uso de un CURSOR por una sentencia WHILE, la cuál nos mejorara el performance en un 75%.
Desde mi punto de vista lo último que se debe de hacer en el diseño de una aplicación es hacer uso de los cursores, ya que consumen muchos recursos y son muy lentos. Así que debemos de tomarlos como la última alternativa en un desarrollo.
Supongamos que tenemos el siguiente cursor
DECLARE @item_category_id INT
DECLARE @order_id INT
DECLARE @purchase_order_id INT
DECLARE item_cursor CURSOR FAST_FORWARD FOR
SELECT
it.item_category_id
,ord.order_id
FROM dbo.item_categories it
INNER JOIN dbo.orders ord
ON ord.item_category_id = it.item_category_id
WHERE ord.order_date >= '1-sep-05'
and it.isSuspended != 1
OPEN item_cursor
FETCH NEXT FROM item_cursor INTO
@item_category_id
,@order_id
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC dbo.usp_generate_purchase_order @item_category_id, @order_id, @purchase_order_id OUTPUT
/*
Codigo extra propio de nuestra aplicación
*/
FETCH NEXT FROM item_cursor INTO
@item-category_id
,@order_id
END
Ahora este es el codigo sin la necesidad de hacer uso de cursores y que nos da el mismo resultado usando un loop While.
--Declarando Variables
DECLARE @item_category_id INT
DECLARE @order_id INT
DECLARE @purchase_order_id INT
--Declarando tabla
DECLARE @item_table TABLE (primary_key INT IDENTITY(1,1) NOT NULL, --THE IDENTITY STATEMENT IS IMPORTANT!
item_category_id INT,
order_id INT
)
--Insertar los registros en nuestra tabla tal y como se seleccionaban en el Cursor
INSERT INTO @item_table
SELECT
it.item_category_id
,ord.order_id
FROM dbo.item_categories it
INNER JOIN dbo.orders ord
ON ord.item_category_id = it.item_category_id
WHERE ord.order_date >= '1-sep-05'
and it.isSuspended != 1
DECLARE @item_category_counter INT
DECLARE @loop_counter INT
SET @loop_counter = ISNULL((SELECT COUNT(*) FROM @item_table),0) -- Hacer el conteo de registros de nuestra tabla
SET @item_category_counter = 1
WHILE @loop_counter > 0 AND @item_category_counter <= @loop_counter
BEGIN
SELECT @item_category_id = item_category_id
,@order_id = order_id
FROM @item_table
WHERE primary_key = @item_category_counter
--Ahora pasar el item-category_id y order_id al store procedure
EXEC dbo.usp_generate_purchase_order @item_category_id, @order_id, @purchase_order_id OUTPUT
/*
Codigo extra de nuestra aplicación
*/
SET @item_category_counter = @item_category_counter + 1
END
Este cambio nos mejora el performance en un 75%, a comparación de un CURSO. Existen algunos casos que no son muy comunes, en el cuál es preferible hacer uso de un cursor, pero en un 99% solo te va a alentar tu aplicación, así que evita hacer uso de ellos.