2008-08-31 11 views
6

Il est généralement admis que l'utilisation de curseurs dans les procédures stockées doit être évitée autant que possible (remplacée par une logique basée sur un ensemble, etc.). Si vous prenez les cas où vous avez besoin d'itérer sur certaines données, et que vous pouvez le faire en lecture seule, est-ce que le curseur d'avance rapide (en lecture seule) est plus ou moins inefficace que par exemple en boucle? De mes enquêtes, il semble que l'option du curseur est généralement plus rapide et utilise moins de lectures et de temps CPU. Je n'ai pas fait de tests approfondis, mais est-ce ce que les autres trouvent? Est-ce que les curseurs de ce type (avance rapide) entraînent des frais supplémentaires ou des ressources qui pourraient être coûteuses et que je ne connais pas.Curseurs SQL Server Fast Forward

est d'autant parler de ne pas utiliser les curseurs vraiment à éviter l'utilisation des curseurs lorsque des approches basées sur des ensembles sont disponibles, et l'utilisation des curseurs actualisables etc.

Merci

Répondre

-2

La «meilleure pratique» d'éviter les curseurs dans SQL Server remonte à SQL Server 2000 et versions antérieures. La réécriture du moteur dans SQL 2005 a résolu la plupart des problèmes liés aux problèmes de curseurs, en particulier avec l'introduction de l'option d'avance rapide. Les curseurs ne sont pas forcément pires que ceux basés sur les ensembles et sont largement utilisés avec succès dans Oracle PL/SQL (LOOP).

Le 'généralement accepté' que vous référez à était valide, mais est maintenant obsolète et incorrect - faites l'hypothèse que les curseurs d'avance rapide se comportent comme annoncé et fonctionnent. Faites des tests et de la recherche, en se basant vos conclusions sur SQL2005 et plus tard

+4

Bien que les curseurs soient utilisés avec succès dans Oracle PL/SQL, cela n'a aucune incidence sur leur utilisation dans SQL Server. La dernière fois que j'ai utilisé Oracle, vous ne pouviez pas écrire des instructions INSERT ... FROM ou UPDATE ... FROM et vous deviez donc utiliser des curseurs. Les modèles de verrouillage sont entièrement différents, donc je ne pense pas que la comparaison soit juste. –

+4

Non, Simon. Ce n'est ni "obsolète" ni "incorrect". Bien que MS puisse avoir amélioré la façon dont les curseurs sont traités et à l'exception de certaines tâches administratives, les curseurs sont nécessairement pire que le code basé sur les ensembles correctement écrit ... même dans Oracle. –

1

Les gens évitent le curseur généralement parce qu'ils sont plus difficiles à écrire qu'une simple boucles while, cependant, une boucle while peut être chère car vous sélectionnez constamment les données d'une table, temporaire ou autre.

Avec un curseur, qui est en lecture seule en avance rapide, les données sont conservées en mémoire et ont été spécialement conçues pour la boucle. Met en évidence qu'un curseur moyen s'exécute 50 fois plus vite qu'une boucle while.

17

Alors qu'un curseur avance rapide a quelques optimisations dans Sql Server 2005, il est pas vrai qu'ils sont partout à proximité d'un ensemble requête basée en termes de performance. Il y a très peu de cas où la logique du curseur ne peut pas être remplacée par une requête basée sur un ensemble. Les curseurs seront toujours plus lents, en partie du fait que vous devez interrompre l'exécution pour remplir vos variables locales.

Voici quelques références qui ne seraient la pointe de l'iceberg si vous recherche cette question:

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 vous voulez un même curseur en plus rapide que FAST FORWARD utilisez un curseur STATIC. Ils sont plus rapides que FAST FORWARD. Pas extrêmement rapide mais peut faire la différence.

+0

c'est faux. vérifiez ce lien. http://www.sql-server-performance.com/2007/cursors/ – crsuarezf

1

Cette réponse espère consolider les réponses données à ce jour.

1) Si possible, ensemble utilisé logique à base pour vos requêtes à savoir essayer d'utiliser juste SELECT, INSERT, UPDATE ou DELETE avec les clauses appropriées FROM ou les requêtes imbriquées - celles-ci seront presque toujours plus rapide.

2) Si ce qui précède n'est pas possible, dans SQL Server 2005+ FAST FORWARD, les curseurs sont efficaces et fonctionnent bien et doivent être utilisés de préférence aux boucles While.

2

"Si vous souhaitez un curseur encore plus rapide que FAST FORWARD, utilisez un curseur STATIC, plus rapide que FAST FORWARD, mais pas très rapide mais qui peut faire la différence."

Pas si vite! Selon Microsoft: "Généralement, lorsque ces conversions se produisaient, le type de curseur se dégradait en un type de curseur" plus cher "Généralement, un curseur (FAST) FORWARD-ONLY est le plus performant, suivi par DYNAMIC, KEYSET et enfin STATIC ce qui est généralement le moins performant. "

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

0

Pour répondre aux questions originales Mile ...

Avance rapide, lecture seule, les curseurs statiques (affectueusement connu sous le nom d'un « curseur Hose ») sont généralement aussi vite ou plus vite qu'un Temp Table équivalente et une boucle While car un tel curseur n'est rien de plus qu'une Table Temp et une boucle While qui a été optimisée un peu en coulisse.

Pour ajouter à ce que Eric Z. Beard affiché sur ce fil et de répondre à la question plus de ...

« Est-ce tous les discours de ne pas utiliser les curseurs vraiment à éviter l'utilisation des curseurs lorsque des approches basées sur des ensembles sont disponibles, et l'utilisation de curseurs modifiables, etc.

Oui. À quelques exceptions près, il faut moins de temps et moins de code pour écrire le bon code pour faire la même chose que la plupart des curseurs et a l'avantage d'utiliser beaucoup moins de ressources et beaucoup plus vite qu'un curseur ou une boucle While. D'une manière générale, et à l'exception de certaines tâches administratives, elles devraient être évitées au profit d'un code basé sur des ensembles correctement écrit. Il y a, bien sûr, des exceptions à chaque "règle" mais, dans le cas des curseurs, des boucles While, et d'autres formes de RBAR, la plupart des gens peuvent compter les exceptions d'une part sans utiliser tous les doigts. ;-)

Il y a aussi la notion de "RBAR caché". C'est un code qui semble basé sur un ensemble, mais qui ne l'est pas. Ce type de code «basé sur un ensemble» est la raison pour laquelle certaines personnes ont adopté les méthodes RBAR et disent qu'elles sont «OK». Par exemple, la résolution du problème du total cumulé à l'aide d'une sous-requête agrégée (SUM) avec une inégalité pour générer le total cumulé n'est pas vraiment définie dans mon livre. Au lieu de cela, c'est RBAR sur les stéroïdes parce que, pour chaque ligne calculée, il doit «toucher» de nombreuses autres lignes à un rythme de N * (N + 1)/2. C'est ce que l'on appelle une "jointure triangulaire" et elle est au moins aussi mauvaise qu'une jointure cartésienne complète (Cross Join ou "Square Join").

Bien que MS ait apporté des améliorations à la façon dont les curseurs fonctionnent depuis SQL Server 2005, le terme «curseur rapide» est toujours un oxymore par rapport au code basé sur les ensembles correctement écrit. Cela est également vrai même dans Oracle. J'ai travaillé avec Oracle pendant 3 ans dans le passé, mais mon travail consistait à améliorer les performances du code existant. La plupart des améliorations vraiment substantielles ont été réalisées lorsque j'ai converti des curseurs en code basé sur un ensemble. De nombreux travaux qui nécessitaient auparavant 4 à 8 heures d'exécution étaient réduits à quelques minutes et parfois à quelques secondes.

2

Vous pouvez éviter les curseurs la plupart du temps, mais parfois c'est nécessaire. Gardez à l'esprit que FAST_FORWARD est DYNAMIC ... FORWARD_ONLY que vous pouvez utiliser avec un curseur STATIC.Essayez de l'utiliser sur le problème d'Halloween pour voir ce qui se passe !!!

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

rien ne s'est vraiment passé ... ils ont tous été exécutés en moins de 1 seconde .... – Sauron