63 votes

Pourquoi est-il considéré comme une mauvaise pratique d’utiliser des curseurs dans SQL Server?

Je connaissais certaines raisons de performances à l'époque SQL 7, mais les mêmes problèmes persistent-ils dans SQL Server 2005? Si j'ai un ensemble de résultats dans une procédure stockée sur lequel je veux agir individuellement, les curseurs sont-ils toujours un mauvais choix? Si oui, pourquoi?

102voto

Josef Points 4395

Parce que les curseurs de prendre de la mémoire et de créer des serrures.

Ce que vous êtes vraiment en train de faire est de tenter de force, basés sur la technologie dans le non-défini en fonction de la fonctionnalité. Et en toute honnêteté, je me dois de souligner que les curseurs ne avez un emploi, mais ils sont mal vus parce que beaucoup de gens qui ne sont pas habitués à l'utilisation de solutions basées sur l'utilisation de curseurs au lieu d'essayer de comprendre le jeu de base de la solution.

Mais, lorsque vous ouvrez un curseur, vous êtes essentiellement le chargement de ces lignes dans la mémoire et en les enfermant, le potentiel de création de blocs. Ensuite, lorsque vous passez le curseur, vous apportez des modifications à d'autres tables et conservant la totalité de la mémoire et des écluses du curseur ouvert.

Tous qui a le potentiel de causer des problèmes de performance pour les autres utilisateurs.

Donc, en règle générale, les curseurs sont désapprouvées. Surtout si c'est la première solution est arrivée à dans la résolution d'un problème.

24voto

Daniel P Points 251

Les commentaires ci-dessus sur SQL être un jeu basé sur l'environnement sont tout à fait vrai. Cependant, il ya des moments où, rang par rang opérations sont utiles. Envisager une combinaison de métadonnées et dynamique-sql.

Un exemple très simple, et dire que j'ai+ de 100 enregistrements dans une table qui définissent les noms des tables que je veux copier/truncate/whatever. Qui est le meilleur? Coder en dur le SQL pour faire ce dont j'ai besoin? Ou itérer à travers ce jeu de résultats et de l'utilisation de dynamic-SQL (sp_executesql) pour effectuer les opérations?

Il n'existe aucun moyen pour atteindre l'objectif ci-dessus à l'aide de set à base SQL.

Donc, pour utiliser les curseurs ou une boucle while (pseudo-curseurs)?

SQL Curseurs sont très bien aussi longtemps que vous utilisez les options correctes:

INSENSIBLE à la volonté de créer une copie temporaire de votre jeu de résultats (ce qui évite d'avoir à le faire vous-même pour votre pseudo-curseur).

READ_ONLY sera assurez-vous qu'aucun des verrous sont placés sur le résultat sous-jacent défini. Les changements dans le résultat sous-jacent sera reflété dans la suite des extractions (comme si le fait d'avoir 1 à partir de votre pseudo-curseur).

FAST_FORWARD permettra de créer optimisation de l'avant uniquement, curseur en lecture seule.

Lire sur les options disponibles avant de se prononcer tous les curseurs comme le mal.

16voto

Eduardo Points 95

Il y a un travail autour de sur les curseurs que j'utilise à chaque fois que j'en ai besoin.

- Je créer une variable de table avec une colonne d'identité en elle.

insérer toutes les données dont j'ai besoin pour travailler avec elle.

Puis faire un tout en bloc avec une variable de compteur et de sélectionner les données que je veux de la variable de table avec une instruction select, où l'identité coulumn correspond au compteur.

De cette façon, je n'ai pas de verrouiller n'importe quoi et utilise beaucoup moins de mémoire et de sa sécurité, je ne vais pas perdre quoi que ce soit avec une corruption de la mémoire ou quelque chose comme ça.

Et le bloc de code est facile à voir et à manipuler.

C'est un exemple simple:

DECLARE @TAB TABLE(ID INT IDENTITY, COLUMN1 VARCHAR(10), COLUMN2 VARCHAR(10))

DECLARE @COUNT INT,
        @MAX INT, 
        @CONCAT VARCHAR(MAX), 
        @COLUMN1 VARCHAR(10), 
        @COLUMN2 VARCHAR(10)

SET @COUNT = 1

INSERT INTO @TAB VALUES('TE1S', 'TE21')
INSERT INTO @TAB VALUES('TE1S', 'TE22')
INSERT INTO @TAB VALUES('TE1S', 'TE23')
INSERT INTO @TAB VALUES('TE1S', 'TE24')
INSERT INTO @TAB VALUES('TE1S', 'TE25')

SELECT @MAX = @@IDENTITY

WHILE @COUNT <= @MAX BEGIN
    SELECT @COLUMN1 = COLUMN1, @COLUMN2 = COLUMN2 FROM @TAB WHERE ID = @COUNT

    IF @CONCAT IS NULL BEGIN
        SET @CONCAT = '' 
    END ELSE BEGIN 
        SET @CONCAT = @CONCAT + ',' 
    END

    SET @CONCAT = @CONCAT + @COLUMN1 + @COLUMN2

    SET @COUNT = @COUNT + 1
END

SELECT @CONCAT

11voto

rpetrich Points 25769

Je pense que les curseurs ont mauvaise réputation parce que les débutants du langage SQL les découvrent et pensent "Hey, une boucle for! Je sais comment les utiliser!" et puis ils continuent à les utiliser pour tout.

Si vous les utilisez pour ce pour quoi ils sont conçus, je n’ai rien à redire à cela.

9voto

Michael Haren Points 42641

SQL est un ensemble en fonction de la langue, c'est ce qu'il fait de mieux.

Je pense que les curseurs sont encore un mauvais choix, sauf si vous comprenez assez sur eux pour justifier leur utilisation dans des circonstances limitées.

Une autre raison pour laquelle je n'aime pas les curseurs est la clarté. Le curseur bloc est tellement moche que c'est difficile à utiliser de manière claire et efficace.

Tout ce que dit, sont des cas où un curseur est vraiment le meilleur-qu'ils ne sont pas généralement le cas que les débutants voulez les utiliser pour.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X