Est-ce qu'une requête EXISTS verrouille toujours une table?

IF NOT EXISTS(SELECT * FROM MyTable WITH(nolock) WHERE Key = 'MyKey') INSERT MyTable(Key) Values('MyKey') 

Si la valeur n'existe pas dans la table, la requête acquiert-elle un verrou?

De la docs :

Les indications READUNCOMMITTED et NOLOCK ne s'appliquent qu'aux verrous de données. Toutes les requêtes, y compris celles avec des indications READUNCOMMITTED et NOLOCK, acquièrent des verrous Sch-S (stabilité du schéma) pendant la compilation et l'exécution. Pour cette raison, les requêtes sont bloquées lorsqu'une transaction simultanée contient un verrou Sch-M (modification de schéma) sur la table. Par exemple, une opération de langage de définition de données (DDL) acquiert un verrou Sch-M avant de modifier les informations de schéma de la table. Toutes les requêtes simultanées, y compris celles exécutées avec des indications READUNCOMMITTED ou NOLOCK, sont bloquées lors de la tentative d'acquisition d'un verrou Sch-S. Inversement, une requête contenant un verrou Sch-S bloque une transaction simultanée qui tente d'acquérir un verrou Sch-M. Pour plus d'informations sur le comportement de locking, voir Verrouillage de la compatibilité (moteur de database).

Il n'acquiert donc pas de verrou de données, mais il acquiert tout de même un verrou de stabilité de schéma.

EXISTS va normalement toujours acquérir un verrou. Mais vous avez ajouté un indice qui l'a empêché de le faire, et ce ne sera pas le cas.

L'utilisation d'un indice NOLOCK empêchera en effet le locking des lignes. Juste un heads up cependant, ce genre de «search et insertion» est criblé de problèmes. L'opération n'est pas atomique et deux sessions essayant de le faire provoqueront une condition de concurrency lorsque les deux findont la key manquante et tenteront toutes les deux d'insert, ce qui entraînera une violation de key en double. Est-il également sous-optimal parce que la search d'index se produit deux fois (une fois pour searchr la key, une fois pour localiser la position d'insertion). La solution optimale et correcte consiste à essayer d'insert et de récupérer à partir de l'erreur de key en double si elle existe déjà.

Ce code est vulnérable à l'erreur. Au lieu de cela, vous pouvez essayer:

Placez un index unique sur la table afin qu'il ne soit pas possible d'insert plusieurs lignes conflictuelles, puis insérez simplement. Un conflit génère une erreur que vous devez gérer.

Ou, si les conflits sont une condition attendue et non l'exception, alors vous voudrez faire l'insert / check atomic:

 insert MyTable( [Key] ) select 'MyKey' where not exists ( select * from MyTable where [Key] = 'MyKey' ) 

Notez également que (nolock) et Read Uncommitted ne produisent pas de résultats précis, de par leur design. C'est bon pour les rapports et autres, mais dangereux d'agir sur vos données basées sur une décision qui utilise (nolock).