2008-08-31 14 views
6

En general, se acepta que el uso de cursores en procedimientos almacenados se debe evitar siempre que sea posible (se debe reemplazar con lógica basada en conjuntos, etc.). Si toma los casos en los que necesita iterar sobre algunos datos, y puede hacerlo de manera solo de lectura, ¿el cursor de avance rápido (solo lectura hacia adelante) es más o menos ineficiente que decir al tiempo que los ciclos? A partir de mis investigaciones, parece que la opción de cursor es generalmente más rápida y utiliza menos lecturas y tiempo de CPU. No hice ninguna prueba exhaustiva, pero ¿es esto lo que otros encuentran? Los cursores de este tipo (avance rápido) tienen una carga adicional o un recurso que podría ser costoso y que yo desconozco.SQL Server Fast Forward Cursors

es toda la charla acerca de no usar los cursores realmente acerca de cómo evitar el uso de cursores cuando los enfoques basados ​​en conjunto están disponibles, y el uso de cursores actualizables etc.

Gracias

Respuesta

-2

La 'Mejor práctica' de evitar cursores en SQL Server se remonta a SQL Server 2000 y versiones anteriores. La reescritura del motor en SQL 2005 abordó la mayoría de los problemas relacionados con los problemas de los cursores, particularmente con la introducción de la opción de avance rápido. Los cursores no son necesariamente peores que los basados ​​en conjuntos y se usan extensamente y con éxito en Oracle PL/SQL (LOOP).

La 'generalmente aceptada' que refiere a era válida, pero ahora está desactualizada e incorrecta - suponiendo que los cursores de avance rápido se comportan como se anuncia y se realiza. Hacer algunas pruebas e investigaciones, basando sus conclusiones en SQL2005 y más tarde

+4

Si bien es cierto que los cursores se utilizan con éxito en Oracle PL/SQL, eso realmente no tiene relación con su uso en SQL Server. La última vez que utilicé Oracle, no se pudieron escribir instrucciones INSERT ... FROM o UPDATE ... FROM, por lo que se requería que utilizaras cursores. Los modelos de bloqueo también son completamente diferentes, así que no creo que la comparación sea justa. –

+4

No, Simon. No es "desactualizado" o "incorrecto". Aunque MS puede haber mejorado la forma en que se manejan los cursores y salvo determinadas tareas administrativas, los cursores son necesariamente peores que los códigos escritos correctamente basados ​​en conjuntos ... incluso en Oracle. –

1

La gente evita cursor, ya que generalmente son más difíciles de escribir que un simple ciclo while, sin embargo, un ciclo while puede ser costoso porque constantemente se seleccionan datos de una tabla, temporal o de otro tipo.

Con un cursor, que es de solo lectura, los datos se guardan en la memoria y se han diseñado específicamente para el bucle.

This article destaca que un cursor promedio se ejecuta 50 veces más rápido que un ciclo while.

17

Mientras que un cursor de avance rápido tiene algunas optimizaciones en SQL Server 2005, es no cierto que son en cualquier lugar cerca de una consulta basada conjunto en términos de actuación. Hay muy pocas situaciones donde la lógica del cursor no puede ser reemplazada por una consulta basada en conjuntos. Los cursores siempre serán intrínsecamente más lentos, debido en parte al hecho de que debe seguir interrumpiendo la ejecución para poder llenar sus variables locales.

Estas son algunas referencias, lo que sólo sería la punta del iceberg si la investigación de este tema:

http://www.code-magazine.com/Article.aspx?quickid=060113

http://sqlblog.com/blogs/adam_machanic/archive/2007/10/13/cursors-run-just-fine.aspx

-1

si quieres un aún más rápido cursor de que AVANCE RÁPIDO a continuación, utilizar un cursor ESTÁTICO. Son más rápidos que FAST FORWARD. No es extremadamente rápido pero puede marcar la diferencia.

+0

esto está mal. revisa este enlace http://www.sql-server-performance.com/2007/cursors/ – crsuarezf

1

Esta respuesta espera consolidar las respuestas dadas hasta la fecha.

1) Si es posible, la lógica basada conjunto utilizado para las consultas es decir, tratar de utilizar simplemente SELECT, INSERT, UPDATE o DELETE con los FROM cláusulas o consultas anidadas adecuados - éstos casi siempre será más rápido.

2) Si lo anterior no es posible, entonces en SQL Server 2005+ FAST FORWARD los cursores son eficientes y funcionan bien y deben utilizarse con preferencia a los bucles while.

2

"Si quieres un cursor incluso más rápido que AVANCE RÁPIDO a continuación, utilizar un cursor estático. Ellos son más rápidos que el avance rápido. No es muy rápido, pero pueden hacer una diferencia."

No tan rápido! Según Microsoft:. "Típicamente, cuando se produjeron estas conversiones, el tipo de cursor degradado a un 'más caro' tipo de cursor Generalmente, un (FAST) cursor sólo hacia adelante es la más performant, seguido por DINÁMICO, KEYSET, y finalmente STATIC que generalmente es el menos eficiente ".

de: http://blogs.msdn.com/b/mssqlisv/archive/2006/06/23/644493.aspx

0

Para responder a las preguntas originales de Mile ...

avance rápido, solo lectura, cursores estáticos (cariñosamente conocido como "Manguera de bomberos cursor") suelen ser tan rápido o más rápido que una Tabla de temperatura equivalente y un bucle While porque dicho cursor no es más que una Tabla de temperatura y un bucle While que se ha optimizado un poco detrás de las escenas.

Para añadir a lo que Eric Z. Barba publicada en este hilo y de responder aún más la cuestión de ...

"¿Es todo lo dicho sobre no usar cursores realmente acerca de cómo evitar el uso de cursores cuando Los enfoques basados ​​en conjuntos están disponibles, y el uso de cursores actualizables, etc. "

Sí. Con muy pocas excepciones, se necesita menos tiempo y menos código para escribir el código correcto basado en conjunto para hacer lo mismo que la mayoría de los cursores y tiene el beneficio adicional de utilizar muchos menos recursos y generalmente se ejecuta MUCHO más rápido que un cursor o un ciclo While. En términos generales, y con la excepción de ciertas tareas administrativas, deberían evitarse a favor de un código basado en conjuntos correctamente escrito. Hay, por supuesto, excepciones a cada "regla" pero, en el caso de los cursores, bucles While y otras formas de RBAR, la mayoría de las personas puede contar las excepciones con una mano sin usar todos los dedos. ;-)

También existe la noción de "RBAR Oculto". Este es un código que parece estar basado en conjuntos, pero en realidad no lo es. Este tipo de código "basado en conjuntos" es la razón por la cual ciertas personas han adoptado los métodos RBAR y dicen que están "OK". Por ejemplo, resolver el problema del total acumulado utilizando una subconsulta correlacionada agregada (SUM) con una desigualdad en él para generar el total acumulado no está realmente establecida en mi libro. En cambio, es RBAR con esteroides porque, para cada fila calculada, tiene que "tocar" repetidamente muchas otras filas a una tasa de N * (N + 1)/2. Eso se conoce como "unión triangular" y es al menos la mitad de malo que una unión cartesiana completa (unión cruzada o "unión cuadrada").

Aunque MS ha realizado algunas mejoras en cómo funcionan los cursores desde SQL Server 2005, el término "Fast Cursor" sigue siendo un oxímoron en comparación con el código escrito correctamente establecido. Eso también es cierto incluso en Oracle. Trabajé con Oracle durante 3 años en el pasado, pero mi trabajo consistía en mejorar el rendimiento del código existente. La mayoría de las mejoras realmente sustanciales se realizaron cuando convertí los cursores al código basado en conjuntos. Muchos trabajos que antes tardaban de 4 a 8 horas en ejecutarse se redujeron a minutos y, a veces, a segundos.

2

Puede evitar cursores mayor parte del tiempo, pero a veces es necesario.

Hemos de tener en cuenta que FAST_FORWARD es dinámico ... FORWARD_ONLY puede utilizar con un cursor estático.

¡Intenta usarlo en el problema de Halloween para ver qué pasa!

IF OBJECT_ID('Funcionarios') IS NOT NULL 
DROP TABLE Funcionarios 
GO 

CREATE TABLE Funcionarios(ID   Int IDENTITY(1,1) PRIMARY KEY, 
          ContactName Char(7000), 
          Salario  Numeric(18,2)); 
GO 

INSERT INTO Funcionarios(ContactName, Salario) VALUES('Fabiano', 1900) 
INSERT INTO Funcionarios(ContactName, Salario) VALUES('Luciano',2050) 
INSERT INTO Funcionarios(ContactName, Salario) VALUES('Gilberto', 2070) 
INSERT INTO Funcionarios(ContactName, Salario) VALUES('Ivan', 2090) 
GO 

CREATE NONCLUSTERED INDEX ix_Salario ON Funcionarios(Salario) 
GO 

-- Halloween problem, will update all rows until then reach 3000 !!! 
UPDATE Funcionarios SET Salario = Salario * 1.1 
    FROM Funcionarios WITH(index=ix_Salario) 
WHERE Salario < 3000 
GO 

-- Simulate here with all different CURSOR declarations 
-- DYNAMIC update the rows until all of then reach 3000 
-- FAST_FORWARD update the rows until all of then reach 3000 
-- STATIC update the rows only one time. 

BEGIN TRAN 
DECLARE @ID INT 
DECLARE TMP_Cursor CURSOR DYNAMIC 
--DECLARE TMP_Cursor CURSOR FAST_FORWARD 
--DECLARE TMP_Cursor CURSOR STATIC READ_ONLY FORWARD_ONLY 
    FOR SELECT ID 
      FROM Funcionarios WITH(index=ix_Salario) 
     WHERE Salario < 3000 

OPEN TMP_Cursor 

FETCH NEXT FROM TMP_Cursor INTO @ID 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    SELECT * FROM Funcionarios WITH(index=ix_Salario) 

    UPDATE Funcionarios SET Salario = Salario * 1.1 
    WHERE ID = @ID 

    FETCH NEXT FROM TMP_Cursor INTO @ID 
END 

CLOSE TMP_Cursor 
DEALLOCATE TMP_Cursor 

SELECT * FROM Funcionarios 

ROLLBACK TRAN 
GO 
+0

nada sucedió realmente ... todos ejecutaron en menos de 1 segundo ... – Sauron