web-dev-qa-db-fra.com

Curseur statique et où le courant de

Le curseur statique ne permet pas de modifier les données car il est en lecture seule, et lorsqu'il est exécuté avec "où le courant de", il renvoie une erreur comme prévu. Jusqu'ici tout va bien. Mais j'ai été surpris de constater que le curseur statique permet de modifier des données avec une variable comme celle-ci.

DECLARE @nome varchar(100), @salario int,@idemp int
DECLARE contact_cursor  CURSOR STATIC FOR
SELECT empno,ename, sal FROM emp


OPEN contact_cursor;


FETCH NEXT from contact_cursor into @idemp,@nome, @salario WHILE @@FETCH_STATUS=0 BEGIN

If @salario < 5000
    Update Emp
    Set Sal = Sal * 1.1
    where empno=@idemp --No error and do the update
    --Where current of contact_cursor; --gives error

print @nome+' '+cast(@salario as varchar(100));
</ code>

Extrait de contact_cursor dans @ idemp, @ nome, @salario [.____] fin Fermer contact_cursor; OffreLocate Contact_cursor;
4
andrea

La principale différence semble être la manière dont chaque approche trouve la ligne à mettre à jour. Le curseur STATIC Curseur copie le résultat complet défini sur une table temporaire cachée en premier (par conséquent, il est en lecture seule), donc cela serait semble Pour être moins efficace pour être moins efficace Re-interrogez la table principale pour chaque UPDATE. Cependant, la mise à jour positionnée semble avoir beaucoup plus de lecture logique et d'opérations. Toutefois, un avantage de la mise à jour positionnée est noté dans la page MSDN pour - [~ # ~] [~ # ~ # ~] :

Courant de

Spécifie que la mise à jour est effectuée à la position actuelle du curseur spécifié.

Une mise à jour positionnée utilisant un courant de la clause met à jour la ligne unique à la position actuelle du curseur. Cela peut être plus précis qu'une mise à jour recherchée qui utilise une clause où la clause permettait de qualifier les lignes à mettre à jour. Une mise à jour recherchée modifie plusieurs lignes lorsque la condition de recherche n'identifie pas de manière unique une seule ligne.

Configuration du test

SET NOCOUNT ON;
-- DROP TABLE ##CursorTest;
CREATE TABLE ##CursorTest ([ID] INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
                           [Val] INT NOT NULL);
INSERT INTO ##CursorTest ([Val]) VALUES (1), (1), (1), (1);

curseur mis à jour et WHERE CURRENT OF

UPDATE ##CursorTest SET [Val] = 1;
SELECT * FROM ##CursorTest;

SET STATISTICS IO ON;
DECLARE curTest CURSOR TYPE_WARNING
  LOCAL
  FORWARD_ONLY
  KEYSET -- removing only reduces logical reads by 4
  SCROLL_LOCKS
  --OPTIMISTIC 
FOR
  SELECT [ID] FROM ##CursorTest WHERE [Val] < 5
  FOR UPDATE OF [Val];

DECLARE @ID INT;
OPEN curTest;

FETCH NEXT
FROM  curTest
INTO  @ID;

WHILE (@@FETCH_STATUS = 0)
BEGIN
  UPDATE tmp
  SET    tmp.[Val] = tmp.[Val] + 2
  FROM   ##CursorTest tmp
  WHERE CURRENT OF curTest;

  FETCH NEXT
  FROM  curTest
  INTO  @ID;
END;

CLOSE curTest;
DEALLOCATE curTest;
SET STATISTICS IO OFF;

SELECT * FROM ##CursorTest;

Résultats:

Table 'Worktable'. Scan count 0, logical reads 8
Table '##CursorTest'. Scan count 1, logical reads 2
Table '##CursorTest'. Scan count 1, logical reads 2
Table 'Worktable'. Scan count 1, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 1, logical reads 2
Table 'Worktable'. Scan count 1, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 1, logical reads 2
Table 'Worktable'. Scan count 1, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 1, logical reads 2
Table 'Worktable'. Scan count 1, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 0
Table 'Worktable'. Scan count 1, logical reads 2

Suppression de l'option KEYSET a réduit les lectures logiques de 4 (je crois), mais ce n'est peut-être pas une épargne sur une requête plus compliquée, éventuellement avec des jointures.

En outre, commutation SCROLL_LOCKS Pour être OPTIMISTIC Augmentation des lectures logiques.

STATIC curseur et standard UPDATE

UPDATE ##CursorTest SET [Val] = 1;
SELECT * FROM ##CursorTest;

SET STATISTICS IO ON;
DECLARE curTest CURSOR TYPE_WARNING
  LOCAL
  FORWARD_ONLY
  STATIC
  OPTIMISTIC 
FOR
  SELECT [ID] FROM ##CursorTest WHERE [Val] < 5;

DECLARE @ID INT;

OPEN curTest;

FETCH NEXT
FROM  curTest
INTO  @ID;

WHILE (@@FETCH_STATUS = 0)
BEGIN
  UPDATE tmp
  SET    tmp.[Val] = tmp.[Val] + 2
  FROM   ##CursorTest tmp
  WHERE  tmp.[ID] = @ID;

  FETCH NEXT
  FROM  curTest
  INTO  @ID;
END;

CLOSE curTest;
DEALLOCATE curTest;
SET STATISTICS IO OFF;

SELECT * FROM ##CursorTest;

Résultats:

Table 'Worktable'. Scan count 0, logical reads 8
Table '##CursorTest'. Scan count 1, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2

Ces tests simples semblent montrer le curseur STATIC _ UPDATE étant la meilleure option, et une requête plus compliquée pour le curseur pourrait être une différence encore plus grande (en supposant que vous puissiez mettre à jour en fonction de la clé en cluster de la table cible).

Mais, si vous avez une situation où vous ne pouvez pas réduire à une rangée individuelle/n'a pas de valeur clé à utiliser, la mise à jour positionnée serait tout à fait pratique.

4
Solomon Rutzky

Pour mieux comprendre ce comportement de mise à jour, nous devrons peut-être regarder [~ # ~ #] update [~ # ~] Syntaxe, il indique:

Du courant de

Spécifie que la mise à jour est effectuée à la position actuelle du curseur spécifié.

Une mise à jour positionnée utilisant un courant de la clause met à jour la ligne unique à la position actuelle du curseur. Cela peut être plus précis qu'une mise à jour recherchée qui utilise une clause où la clause permettait de qualifier les lignes à mettre à jour. Une mise à jour recherchée modifie plusieurs lignes lorsque la condition de recherche n'identifie pas de manière unique une seule ligne.

Cela signifie donc si vous utilisez "Courant de", c'est une mise à jour sur le curseur spécifié et avec un curseur statique (qui est en lecture seule), Nous obtiendrons l'erreur que vous avez postée.

Cependant, lorsque vous êtes non en utilisant un "courant de", vous effectuez la mise à jour de la table sous-jacente directement, ce qui n'a rien à voir avec Le curseur spécifié n'a donc pas de problème si le curseur est réadien ou non.

Aussi selon la définition du curseur statique sur MSDN

STATIQUE

Définit un curseur qui fait une copie temporaire des données à utiliser par le curseur. Toutes les demandes au curseur sont traitées de cette table temporaire dans TEMPDB; Par conséquent, les modifications apportées aux tables de base ne sont pas reflétées dans les données renvoyées par des extraçons apportées à ce curseur et ce curseur n'autorise pas les modifications.

Donc, dans ce contexte, lorsque vous effectuez des mises à jour de la table sous-jacente de ce curseur statique, les modifications ne seront pas reflétées sur le curseur (c'est-à-dire la table temporaire qui représente le curseur).

Si je peux faire un résumé rapide logique (à ma propre compréhension)

Lorsque vous créez un curseur statique, une table de temporisation dans [TEMPDB] est créée et cette table TEMP est en lecture seule, ce qui signifie que vous ne pouvez pas utiliser le courant de référence pour vous reporter à cette table TEMP et effectuer des mises à jour.

Mais vous pouvez faire ce que vous voulez faire à la table sous-jacente (pour ce curseur statique)

3
jyao