Pourquoi NOLOCK est ignorée « dans la clause FROM qui s'appliquent à la table cible d'une instruction UPDATE ou DELETE »?

StackOverflow https://stackoverflow.com/questions/4322368

Question

Je suis confus par la phrase BOL:

  

« READUNCOMMITTED et NOLOCK ne peuvent pas être spécifiés pour les tables modifiées par insertion, mise à jour ou les opérations de suppression. L'optimiseur de requêtes SQL Server ignore les conseils READUNCOMMITTED et NOLOCK dans la clause FROM qui s'appliquent à la table cible d'une instruction UPDATE ou DELETE » [1]

Par exemple, si j'écris

--script 1) 
UPDATE Test SET Txt=(Select Txt from TEST WITH(NOLOCK) where ID=1) 
WHERE ID=1

il est exécuté sans erreurs (ou avertissements) et est probablement équivalent à

--script 2)
set transaction isolation level SERIALIZABLE;
begin tran
Declare @nvarm nvarchar(max);

Select @nvarm=Txt from Test where ID=1;
--Select @nvarm;
UPDATE Test  SET Txt=@nvarm  WHERE ID=1;
commit;

qui est également exécutée sans erreurs ou avertissements.
Est-il équivalent?

Le tableau est le même, mais dans FROM il est logiquement la table source et non la table cible Je pourrais avoir réécrite 1) avec une table source différente comme une autre table (physique):

--script 3)
select *
into testDup
from TEST;

GO;

UPDATE Test SET Txt=(SELECT Txt FROM TestDUP WITH(NOLOCK) where ID=1) 
    WHERE ID=1

Pourquoi NOLOCK être ignorée sur une autre table
Ou, si elle est fausse, alors la question
Comment écrire ACTUALISATION ayant « des notes de NOLOCK dans la clause FROM qui s'appliquent à la table cible d'une instruction UPDATE ou DELETE » parce que même en 1) et 2) la table physique est la même, mais logiquement la source (dans SELECT) table et cible (UPDATE) tableau sont différents petits.

Comment écrire une instruction UPDATE démontrant que WITH (NOLOCK) est ignorée?
Pourquoi devrait-il être ignoré du tout? Est-il ignoré?
Ou, si elle est une mauvaise question,
Pourquoi la syntaxe ne permet l'indice qui est garanti d'être ignoré?

Encore une fois, que ce soit il est impossible (ou est-il?) D'écrire déclaration telle que écrit dans la documentation ou je ne comprends pas le sens de « ne tient pas » (Quel est le sens de l'ignorer? Ou de l'avoir à tous?) ...

MAJ2:
Les réponses montrent que NOLOCK est pas (mis à jour) ignoré dans la clause FROM de l'instruction UPDATE ce qui est affirmé par BOL docs [1].
Eh bien, l'essence de cette question:
Pouvez-vous me donner un exemple (contexte) où ignorant de NOLOCK dans la clause FROM de l'instruction UPDATE aurait été logique?

[1]
Tableau Conseils (Transact-SQL)
SQL Server 2008 R2
http://msdn.microsoft.com/en-us/library/ms187373.aspx

Était-ce utile?

La solution

La clause FROM d'une instruction UPDATE ou DELETE n'est pas évidente dans l'un de vos exemples. Vous avez des clauses dans les sous-requêtes, mais ce ne sont pas la même chose.

Voici une clause FROM pour une instruction UPDATE:

UPDATE t
SET Col = u.Val
FROM   /* <-- Start of FROM clause */
   Table t WITH (NOLOCK)
       inner join
   Table2 u
       on
          t.ID = u.ID
/* End of FROM clause */
WHERE
    u.Colx = 19

Et, comme la documentation appelle, le WITH (NOLOCK) sera ignoré dans ce cas. Quant à savoir pourquoi cela est permis si elle va être ignorée, une supposition serait qu'une telle indication serait valable dans la version SELECT de la « même » requête, et les gens ne SELECTs souvent écrire (pour vous assurer qu'ils sont ciblant le bon lignes / colonnes), puis remplacer la clause SELECT avec un UPDATE / SET paire de clauses, et peuvent laisser le reste de la requête modifiée.


Mise à jour basée sur un commentaire / "réponse" de vgv8:

Votre exemple est mise à jour à la recherche toujours pas à la clause FROM de l'instruction UPDATE

Ce qui suit fonctionne très bien, même avec le TABLOCKX () ouvert sur l'autre connexion:

UPDATE T  SET Txt= td.Txt
FROM TEST t inner join TESTDUP td  WITH (NOLOCK) on t.ID = td.ID
where t.ID = 1

Autres conseils

Non devinant nécessaire.

Sybase et l'utilisation de MS SQL server un verrouillage des ressources 2PL interne, automatique, mais avec la pleine conformité avec la / ISO / CEI norme ANSI SQL. La syntaxe devient stupide lorsque vous essayez de comprendre toutes les combinaisons possibles, parce que certaines clauses ne sont pas pertinentes pour chaque commande.

Qu'est-ce que le manuel essaie de dire, mais ne dit pas en anglais simple, est:

  • pour quelque opération extérieure, ou une seule requête dans une transaction, vous effectuez, vous pouvez SET ISOLATION LEVEL
  • qui peut être spécifié à l'aide UNCOMMITTED, NOLOCK, HOLDLOCKsyntax et
  • où vous avez un IL dans la requête externe, ou une seule requête dans une transaction, mais que vous souhaitez utiliser un autre IL pour la requête interne, qui peut être fait (utiliser différents modulateurs sur la requête interne)
  • pour que vous puissiez avoir une transaction à exécution IL3, et avoir un SELECT en son sein à l'exécution IL0 ou IL1

Par ailleurs:

  • quel que soit ce que vous pensez que vous faites, ou si vous voulez faire, puisque le verrouillage est automatique, et ISOLATION LEVEL 3is requis pour UPDATES et DELETES, dans laquelle READ UNCOMMITTED et NOLOCK ne sont pas applicables, et ne peut être utilisé , si vous avez utilisé les le serveur les ignorer

Après avoir créé et rempli 2 tables identiques Test et TestDUP [1], dans une session (fenêtres de SSMS) J'exécute

--2)
begin tran
Select Txt from TestDUP  with(TABLOCKX) 
WHERE ID=1
--rollback

SELECT qui bloque d'une autre session (fenêtre SGSS) sur la même table, par exemple:

 --3.1)
select * from TestDUP

mais pas

 --3.2)
select * from TestDUP WITH(NOLOCK)

Notez que 3.1) est bloqué, mais 3.2) n'est pas.

Bien, la mise à jour sur un autre test de table en utilisant SELECT de TestDUP

--4)WITH(NOLOCK) is not honored until completing
-- (commit/roollback)-ing transaction 2)
UPDATE Test  SET Txt=
(Select Txt from TESTDUP WITH(NOLOCK)  where ID=1)
  WHERE ID=1;

est bloqué car avec (NOLOCK), sur une autre table source, est ignorée dans la clause FROM de l'instruction UPDATE.

Mise à jour:

--4.1)WITH(NOLOCK) is honored 
-- in FROM clause of UPDATE statement 
UPDATE Test  SET Txt= td.Txt
FROM TESTDUP td  WITH (NOLOCK)
where test.ID = 1 

--4.2) Note that without NOLOCK this script is blocked
-- until first transaction 2) completes (rollbacks or commits)
UPDATE Test  SET Txt= td.Txt
FROM TESTDUP td  WITH (NOLOCK)
where test.ID = 1  

Ainsi, il est maintenant logique, mais elle contredit la documentation depuis NOLOCK dans la clause FROM de l'instruction UPDATE est pas ignoré, non?

[1]
Créer 2 tables remplies de manière identique Test et testDUP:

if object_id('Test') IS not NULL
drop table Test;

CREATE TABLE Test (
  ID int IDENTITY PRIMARY KEY,
  Txt nvarchar(max) NOT NULL
)
GO
-----------
INSERT INTO Test
SELECT REPLICATE(CONVERT(nvarchar(max), 
     CHAR(65+ABS(CHECKSUM(NEWID()))%26)),100000)
GO 10

--COPYING TEST into TESTDUP with creating of the latter
select *
into testDup
from TEST;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top