Qu'est-ce que «avec (nolock)» dans SQL Server?

610

Quelqu'un peut-il expliquer les implications de l'utilisation with (nolock)sur les requêtes, quand vous devriez / ne devriez pas l'utiliser?

Par exemple, si vous avez une application bancaire avec des taux de transaction élevés et beaucoup de données dans certaines tables, dans quels types de requêtes nolock serait-il correct? Y a-t-il des cas où vous devriez toujours l'utiliser / ne jamais l'utiliser?

Andy White
la source
J'ai subquestionné dans stackoverflow.com/questions/3836282/… et stackoverflow.com/questions/3836032/… surtout la réponse de Jonathan Allen stackoverflow.com/questions/686724/…
Gennady Vanin Геннадий Ванин
1
un lien ici - mssqltips.com/sqlservertip/2470/…
Steam
1
Voici un excellent résumé des implications de l'utilisation de NOLOCK blogs.msdn.com/b/davidlean/archive/2009/04/06/…
Bryan

Réponses:

461

WITH (NOLOCK) équivaut à utiliser READ UNCOMMITED comme niveau d'isolement des transactions. Vous risquez donc de lire une ligne non validée qui est ensuite annulée, c'est-à-dire des données qui ne sont jamais entrées dans la base de données. Ainsi, bien qu'il puisse empêcher le blocage des lectures par d'autres opérations, il présente un risque. Dans une application bancaire avec des taux de transaction élevés, ce ne sera probablement pas la bonne solution à tout problème que vous essayez de résoudre à mon humble avis.

David M
la source
156
La plupart des applications bancaires peuvent utiliser nolock en toute sécurité car elles sont transactionnelles au sens commercial. Vous écrivez uniquement de nouvelles lignes, vous ne les mettez jamais à jour.
Jonathan Allen
49
@ Grauenwolf- Une ligne insérée mais non validée peut encore conduire à des lectures sales.
saasman
16
@ Saasman - Si vous n'annulez jamais de transactions, cela n'a pas d'importance. Et avec une table à insert uniquement, les chances de retour en arrière sont minimes. Et s'ils se produisent, vous corrigerez toujours tout dans le rapport de variance de fin de journée.
Jonathan Allen
1
Je suis retranché. Je suppose que les astuces No Lock non ajoutées. Pour Examp:
Ross Bush
11
Si vous utilisez NOLOCKavec un, SELECTvous courez le risque de renvoyer les mêmes lignes plus d'une fois (données dupliquées) si des données sont jamais insérées (ou mises à jour) dans la table lors d'une sélection.
Ian Boyd
170

La question est de savoir ce qui est pire:

  • une impasse, ou
  • une mauvaise valeur?

Pour les bases de données financières, les blocages sont bien pires que les valeurs erronées. Je sais que ça sonne à l'envers, mais écoutez-moi. L'exemple traditionnel des transactions de base de données consiste à mettre à jour deux lignes en soustrayant l'une et en ajoutant à une autre. C'est faux.

Dans une base de données financières, vous utilisez des transactions commerciales. Cela signifie ajouter une ligne à chaque compte. Il est de la plus haute importance que ces transactions se terminent et que les lignes soient correctement écrites.

Obtenir le solde du compte temporairement incorrect n'est pas un gros problème, c'est à cela que sert le rapprochement de fin de journée. Et un découvert d'un compte est beaucoup plus susceptible de se produire parce que deux distributeurs automatiques de billets sont utilisés à la fois qu'en raison d'une lecture non validée d'une base de données.

Cela dit, SQL Server 2005 a corrigé la plupart des bogues qui ont rendu NOLOCKnécessaire. Donc, à moins que vous n'utilisiez SQL Server 2000 ou une version antérieure, vous ne devriez pas en avoir besoin.

Lectures complémentaires au
niveau des lignes

Jonathan Allen
la source
22
Obtenir un solde de compte temporairement erroné n'est pas un problème? Que se passe-t-il si cette transaction est celle où vous retirez de l'argent d'un distributeur sans limite de découvert?
Apprendre
13
@Learning: que se passe-t-il si vous retirez l'argent 30 secondes avant que quelqu'un ne débite votre carte? Tant que toute communication ne sera pas instantanément instantanée, les découverts deviendront réalité.
Jonathan Allen
6
+1 Dans l'application financière (partout, pas seulement dans les banques), il n'y a ni mises à jour ni suppressions. Même les opérations incorrectes sont corrigées en insérant des enregistrements. Quel est ce terme en anglais? Est-ce "storno"? Google ne m'a pas aidé à répondre à cette question
Gennady Vanin Геннадий Ванин
7
Entrée tardive ... les blocages doivent être capturés et réessayés. Les lectures sales ont des conséquences
GBN
4
@JonathanAllen juste un fyi, le terme est UTmost, pas UP.
Jimmy D
57

Malheureusement, il ne s'agit pas seulement de lire des données non validées. En arrière-plan, vous pouvez finir par lire des pages deux fois (dans le cas d'un fractionnement de page), ou vous risquez de manquer complètement les pages. Vos résultats peuvent donc être très biaisés.

Consultez l'article d' Itzik Ben-Gan . Voici un extrait:

"Avec l'indication NOLOCK (ou en définissant le niveau d'isolement de la session sur LIRE NON COMMIS), vous dites à SQL Server que vous ne vous attendez pas à la cohérence, donc il n'y a aucune garantie. Gardez à l'esprit que" données incohérentes "ne signifie pas seulement que vous pouvez voir des modifications non validées qui ont été annulées ultérieurement, ou des modifications de données dans un état intermédiaire de la transaction. Cela signifie également que dans une requête simple qui analyse toutes les données de table / index, SQL Server peut perdre la position d'analyse, ou vous pouvez vous retrouver obtenir deux fois la même ligne . "

sqlbelle
la source
5
Un peu plus loin, il explique comment obtenir deux fois la même ligne: je vais recréer la table T1 de sorte que l'index cluster sur col1 soit défini comme un index unique avec l'option IGNORE_DUP_KEY. Cela signifie que les valeurs en double ne peuvent pas exister dans col1, et également qu'une tentative d'insertion d'une clé en double n'échouera pas la transaction et ne générera pas d'erreur, mais générera simplement un avertissement. Si vous n'utilisez pas cette option bizarre, vous n'avez probablement pas à vous soucier d'obtenir deux fois des lignes
JanHudecek
Vous pouvez toujours obtenir des lignes de dupe même sans l'option filaire - si votre requête exploite un index qui n'est pas unique, par exemple. Ce n'est pas unique à nolock, cependant.
RMD
54

L'exemple de manuel pour l'utilisation légitime de l'indice nolock est l'échantillonnage de rapports par rapport à une base de données OLTP à haute mise à jour.

Pour prendre un exemple d'actualité. Si une grande banque américaine a voulu générer un rapport horaire à la recherche des premiers signes d'une exécution au niveau de la ville sur la banque, une requête nolock pourrait parcourir les tableaux de transactions résumant les dépôts en espèces et les retraits en espèces par ville. Pour un tel rapport, le minuscule pourcentage d'erreur causé par les transactions de mise à jour annulées ne réduirait pas la valeur du rapport.

saasman
la source
31

Vous ne savez pas pourquoi vous n'encapsulez pas les transactions financières dans les transactions de la base de données (comme lorsque vous transférez des fonds d'un compte à un autre - vous ne validez pas un côté de la transaction à la fois - c'est pourquoi des transactions explicites existent). Même si votre code est braindead pour les transactions commerciales comme il semble, toutes les bases de données transactionnelles ont le potentiel de faire des annulations implicites en cas d'erreurs ou d'échecs. Je pense que cette discussion est bien au-dessus de votre tête.

Si vous rencontrez des problèmes de verrouillage, implémentez la gestion des versions et nettoyez votre code.

Aucun verrou ne renvoie non seulement des valeurs erronées, mais également des enregistrements fantômes et des doublons.

Il est faux de croire que cela accélère toujours l'exécution des requêtes. S'il n'y a pas de verrous en écriture sur une table, cela ne fait aucune différence. S'il y a des verrous sur la table, cela peut rendre la requête plus rapide, mais il y a une raison pour laquelle les verrous ont été inventés en premier lieu.

En toute justice, voici deux scénarios spéciaux où un indice nolock peut fournir une utilité

1) Base de données du serveur SQL antérieure à 2005 qui doit exécuter une longue requête sur la base de données OLTP en direct, cela peut être le seul moyen

2) Une application mal écrite qui verrouille les enregistrements et renvoie le contrôle à l'interface utilisateur et les lecteurs sont bloqués indéfiniment. Nolock peut être utile ici si l'application ne peut pas être corrigée (tierce partie, etc.) et que la base de données est antérieure à 2005 ou que le contrôle de version ne peut pas être activé.

Andrew
la source
11
Je suis d'accord avec vous que NOLOCK ne doit pas être utilisé pour compenser un code mal écrit. Cependant, je pense que votre attaque contre Johnathan est injustifiée car il n'a jamais mentionné les transactions de base de données . Il a simplement souligné que les applications financières ne permettent généralement pas de modifier les enregistrements (il y a évidemment des exceptions). Dans votre exemple de transfert de fonds, il dit qu'il serait étrange que vous modifiiez la valeur du solde du compte au lieu d' ajouter une entrée de débit / crédit à une sorte de grand livre.
chrnola
19
Lorsque des fonds sont transférés d'un compte à un autre dans différentes banques, que se passe-t-il selon vous? Une uber-base de données prend un verrou sur une table à Bank of America et un autre à Wells Fargo? Non. Une transaction financière est écrite pour chacun, puis un processus de fin de journée vérifie que tous les enregistrements correspondent.
Jonathan Allen
24

NOLOCKest équivalent à READ UNCOMMITTED, cependant Microsoft dit que vous ne devez pas l'utiliser pour les instructions UPDATEor DELETE:

Pour les instructions UPDATE ou DELETE: cette fonctionnalité sera supprimée dans une future version de Microsoft SQL Server. Évitez d'utiliser cette fonctionnalité dans de nouveaux travaux de développement et prévoyez de modifier les applications qui utilisent actuellement cette fonctionnalité.

http://msdn.microsoft.com/en-us/library/ms187373.aspx

Cet article s'applique à SQL Server 2005, donc la prise en charge NOLOCKexiste si vous utilisez cette version. Afin de pérenniser votre code (en supposant que vous avez décidé d'utiliser des lectures sales), vous pouvez l'utiliser dans vos procédures stockées:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

Seibar
la source
21

Vous pouvez l'utiliser lorsque vous ne lisez que des données, et vous ne vous souciez pas vraiment de savoir si vous récupérez des données qui ne sont pas encore validées.

Cela peut être plus rapide lors d'une opération de lecture, mais je ne peux pas vraiment dire de combien.

En général, je déconseille de l'utiliser - la lecture de données non validées peut être un peu déroutante au mieux.

marc_s
la source
1
ce serait bien si vous mentionniez le fait que SQL Server 2005 a le versionnage des lignes afin que les nolocks ne soient même plus nécessaires.
Jonathan Allen
Eh bien, le "avec (nolock)" a toujours sa place même dans SQL Server 2005 - mais les avantages deviennent de plus en plus minces, c'est vrai.
marc_s
18

Un autre cas où cela est généralement correct est dans une base de données de rapports, où les données sont peut-être déjà vieillies et les écritures ne se produisent tout simplement pas. Dans ce cas, cependant, l'option doit être définie au niveau de la base de données ou de la table par l'administrateur en modifiant le niveau d'isolement par défaut.

Dans le cas général: vous pouvez l' utiliser lorsque vous êtes très sûr qu'il est correct de lire les anciennes données. La chose importante à retenir est qu'il est très facile de se tromper . Par exemple, même si tout va bien au moment où vous écrivez la requête, êtes-vous sûr que quelque chose ne changera pas dans la base de données à l'avenir pour rendre ces mises à jour plus importantes?

Je vais également 2ème l'idée que ce n'est probablement pas une bonne idée dans l'application bancaire. Ou une application d'inventaire. Ou partout où vous pensez aux transactions.

Joel Coehoorn
la source
4
En tant que personne qui travaille sur des applications bancaires, je dois dire que le verrouillage sans problème n'est pas un problème. Les enregistrements transactionnels, c'est-à-dire les lignes qui sont insérées mais jamais mises à jour ou supprimées, résistent étonnamment aux problèmes de lecture des données non engagées.
Jonathan Allen
15

Réponse simple - chaque fois que votre SQL ne modifie pas les données et que vous avez une requête qui pourrait interférer avec d'autres activités (via le verrouillage).

Cela vaut la peine d'être pris en compte pour toutes les requêtes utilisées pour les rapports, surtout si la requête prend plus de, disons, 1 seconde.

C'est particulièrement utile si vous avez des rapports de type OLAP que vous exécutez sur une base de données OLTP.

La première question à se poser, cependant, est "pourquoi suis-je inquiet à ce sujet?" D'après mon expérience, le trucage du comportement de verrouillage par défaut se produit souvent lorsque quelqu'un est en mode "essayer quelque chose" et c'est un cas où des conséquences inattendues ne sont pas improbables. Trop souvent, il s'agit d'une optimisation prématurée et peut trop facilement être intégré dans une application "au cas où". Il est important de comprendre pourquoi vous le faites, quel problème il résout et si vous avez réellement le problème.

dkretz
la source
11

Réponse courte:

Utilisez uniquement WITH (NOLOCK)dans l'instruction SELECT sur les tables qui ont un index cluster.

Longue réponse:

WITH (NOLOCK) est souvent exploité comme un moyen magique pour accélérer les lectures de bases de données.

Le jeu de résultats peut contenir des lignes qui n'ont pas encore été validées, qui sont souvent annulées ultérieurement.

Si WITH (NOLOCK) est appliqué à une table qui a un index non clusterisé, les index de ligne peuvent être modifiés par d'autres transactions lorsque les données de ligne sont diffusées dans la table de résultats. Cela signifie que l'ensemble de résultats peut manquer de lignes ou afficher plusieurs fois la même ligne.

READ COMMITTED ajoute un problème supplémentaire où les données sont corrompues dans une seule colonne où plusieurs utilisateurs changent la même cellule simultanément.

WonderWorker
la source
2
La lecture de données non validées est acceptable si elle ne modifie pas la décision finale. Par exemple, si vous essayez de prévoir combien d'argent votre magasin de détail va gagner au cours des 6 prochains mois, voir que Tammy a acheté 2 rouleaux de serviettes en papier alors qu'elle en a vraiment acheté 3 ne va pas changer votre opinion sur l'avenir .
Jonathan Allen
1
Si votre filtre inclut maintenant, vos données seront inexactes au moment où vous exécuterez la requête. Si votre filtre ne comprend que des données historiques, l'utilisation READ UNCOMITTED ne l'affectera pas du tout. Il y a une raison pour laquelle il a été inclus dans la norme ANSI.
Jonathan Allen
2
Ne jamais dire jamais. Si vous avez BESOIN que les données soient exactes à 100%, vous ne devez pas utiliser nolock. Pour moi, ce n'est généralement pas le cas. Lors de la présentation de données à un utilisateur, au moment où il agit sur les données, elles peuvent avoir déjà changé de toute façon, mais probablement pas, et la contention de verrouillage ne vaut pas les délais de réponse.
Perposterer
Restons-en aux systèmes dignes d'existence. N'oubliez pas que Tammy a un cerveau parfaitement décent, donc utiliser une base de données pour enregistrer de minuscules achats de serviettes en papier dont personne ne se soucie est au mieux absurde. Nous nous concentrons sur les systèmes qui sont réellement importants, par exemple le fait de payer les gens à temps, de répondre aux urgences, etc. Lorsqu'une personne peut faire un meilleur travail qu'une base de données, envisagez de réaffecter ces ressources.
WonderWorker
10

Mes 2 cents - il est logique d'utiliser WITH (NOLOCK) lorsque vous devez générer des rapports. À ce stade, les données ne changeraient pas beaucoup et vous ne voudriez pas verrouiller ces enregistrements.

SoftwareGeek
la source
2
Je pense que WITH (NoLOCK) est meilleur si vous ne vous souciez pas des changements en cours.
Abdul Saboor
9

Si vous gérez des transactions financières, vous ne voudrez plus jamais les utiliser nolock. nolockest mieux utilisé pour sélectionner parmi de grandes tables qui ont beaucoup de mises à jour et vous ne vous souciez pas si l'enregistrement que vous obtenez pourrait être obsolète.

Pour les enregistrements financiers (et presque tous les autres enregistrements dans la plupart des applications), cela nolockferait des ravages car vous pourriez potentiellement lire les données d'un enregistrement en cours d'écriture et ne pas obtenir les données correctes.

Andrew Hare
la source
5
Étonnamment, lorsque vous travaillez avec des données financières, ce n'est pas un problème. Étant donné que les lignes ne sont jamais modifiées et que les comptes sont rapprochés à la fin de la journée, la lecture de données temporairement fausses ne fait rien.
Jonathan Allen
8

J'ai utilisé pour récupérer un "prochain lot" pour les choses à faire. Peu importe dans ce cas quel élément exact, et j'ai beaucoup d'utilisateurs exécutant cette même requête.

Otávio Décio
la source
1
Nous faisons quelque chose de similaire pour présenter une tâche d'arrière-plan avec une file d'attente de travail à faire. Si, lorsqu'il atteint un enregistrement particulier, il n'existe plus / correspond aux critères de sélection, il passe simplement au suivant.
TripeHound
7

Utilisez nolock lorsque vous êtes d'accord avec les données "sales". Ce qui signifie que nolock peut également lire des données en cours de modification et / ou non validées.

Ce n'est généralement pas une bonne idée de l'utiliser dans un environnement de transactions élevées et c'est pourquoi ce n'est pas une option par défaut sur la requête.

Apprentissage
la source
3
La seule fois où vous en avez besoin, c'est dans un environnement de transactions élevées. Si vos tables sont pour la plupart inactives, vous n'y gagnerez rien.
Jonathan Allen
7

J'utilise avec (nolock) hint en particulier dans les bases de données SQLServer 2000 à forte activité. Je ne suis pas certain cependant qu'il soit nécessaire dans SQL Server 2005. J'ai récemment ajouté cet indice dans un SQL Server 2000 à la demande du DBA du client, car il remarquait de nombreux verrous d'enregistrement SPID.

Tout ce que je peux dire, c'est que l'utilisation de l'indice ne nous a PAS fait de mal et semble avoir résolu le problème de verrouillage. Le DBA de ce client particulier a essentiellement insisté pour que nous utilisions l'indice.

Soit dit en passant, les bases de données avec lesquelles je traite sont des back-ends pour les systèmes de réclamations médicales d'entreprise, nous parlons donc de millions d'enregistrements et de plus de 20 tables dans de nombreuses jointures. J'ajoute généralement un indice WITH (nolock) pour chaque table de la jointure (sauf s'il s'agit d'une table dérivée, auquel cas vous ne pouvez pas utiliser cet indice particulier)

user52212
la source
1
SQL Server 2005 a ajouté le "versionnage de lignes", ce qui devrait réduire considérablement le besoin de nolocks. Nous avons récemment mis à niveau et ne formons pas nos administrateurs de base de données pour qu'ils cessent de les utiliser.
Jonathan Allen
5

La réponse la plus simple est une question simple - avez-vous besoin que vos résultats soient reproductibles? Si oui, NOLOCKS ne convient en aucun cas

Si vous n'avez pas besoin de répétabilité, les nolocks peuvent être utiles, surtout si vous n'avez pas le contrôle sur tous les processus se connectant à la base de données cible.

Ed Green
la source