SQL Server NOLOCK et jointures


153

Contexte: J'ai une requête critique pour les performances que j'aimerais exécuter et je ne me soucie pas des lectures incorrectes.

Ma question est; Si j'utilise des jointures, dois-je également spécifier l'indication NOLOCK sur celles-ci?

Par exemple; est:

SELECT * FROM table1 a WITH (NOLOCK)
INNER JOIN table2 b WITH (NOLOCK) ON a.ID = b.ID

Équivalent à:

SELECT * FROM table1 a WITH (NOLOCK)
INNER JOIN table2 b ON a.ID = b.ID

Ou dois-je spécifier l' (NOLOCK)indication sur la jointure pour m'assurer que je ne verrouille pas la table jointe?

Réponses:


166

Je n'aborderai pas le READ UNCOMMITTED argument, juste votre question initiale.

Oui, vous avez besoin WITH(NOLOCK)sur chaque table de la jointure. Non, vos requêtes ne sont pas les mêmes.

Essayez cet exercice. Commencez une transaction et insérez une ligne dans table1 et table2. Ne pas valider ou annuler la transaction pour le moment. À ce stade, votre première requête retournera avec succès et inclura les lignes non validées; votre deuxième requête ne retournera pas car table2 n'a pas d' WITH(NOLOCK)indice dessus.


18

J'étais presque sûr que vous devez spécifier le NOLOCKpour chacun JOINdans la requête. Mais mon expérience s'est limitée à SQL Server 2005.

Quand j'ai recherché MSDN juste pour confirmer, je n'ai rien trouvé de définitif. Les déclarations ci-dessous semblent me faire penser que pour 2008, vos deux déclarations ci-dessus sont équivalentes, bien que ce ne soit pas le cas pour 2005:

[SQL Server 2008 R2]

Toutes les indications de verrouillage sont propagées à toutes les tables et vues auxquelles le plan de requête accède , y compris les tables et vues référencées dans une vue. En outre, SQL Server effectue les vérifications de cohérence de verrouillage correspondantes.

[SQL Server 2005]

Dans SQL Server 2005, toutes les indications de verrouillage sont propagées à toutes les tables et vues référencées dans une vue. En outre, SQL Server effectue les vérifications de cohérence de verrouillage correspondantes.

De plus, veuillez noter - et cela s'applique à la fois à 2005 et à 2008:

Les indications de table sont ignorées si la table n'est pas accédée par le plan de requête. Cela peut être dû au fait que l'optimiseur a choisi de ne pas accéder du tout à la table, ou parce qu'une vue indexée est accédée à la place. Dans ce dernier cas, l'accès à une vue indexée peut être empêché en utilisant l' OPTION (EXPAND VIEWS)indicateur de requête.


@In Sane: Intéressant ... merci pour ça ... Je suppose que je ne fais pas de mal en l'incluant sur JOINS, même si ce n'est pas entièrement nécessaire? La documentation sur NOLOCK est assez rare comme vous l'avez mentionné; J'ai eu du mal à trouver moi-même quoi que ce soit de concluant.
DanP

2
@InSane: D'où avez-vous obtenu ces informations? Cela semble aller à l'encontre de la réponse acceptée.
Jay Sullivan

1
@notfed - reportez-vous au lien technet technet.microsoft.com/en-us/library/ms187373(v=sql.105).aspx - vous pouvez changer la version de la base de données en haut pour comparer le même article pour différentes versions de la base de données
Jagmag

2
Le texte de 2005 parle de VIEWS. Donc, si vous faites "from myview with (nolock)", cela indique que le nolock est propagé à toutes les tables et vues impliquées dans myview (vous pourriez avoir 10 jointures là-dedans). Je ne sais pas ce que signifie exactement le texte de 2008 car il ajoute «accessible par le plan de requête» en plus des vues.
Thierry_S

9

Ni. Vous définissez le niveau d'isolement READ UNCOMMITTEDauquel il est toujours préférable de donner des conseils de verrouillage individuels. Ou, mieux encore, si vous vous souciez de détails tels que la cohérence , utilisez l' isolement de snapshot .


@Remus: Je ne suis pas sûr de pouvoir utiliser READ UNCOMMITTED dans mon cas car j'accède à la connexion via NHibernate pour effectuer un appel ADO.NET brut spécial; cela peut-il être spécifié en ligne dans la requête, ou obéira-t-il au niveau de transaction présent sur la transaction NHibernate?
DanP

Enveloppez l'appel using (TransactionScope scope=new TransactionScope(..., TransactionOptions) {...}et définissez les IsolationLeveloptions: msdn.microsoft.com/en-us/library
Remus Rusanu

@Remus: Malheureusement, la gestion des transactions est prise en charge à un niveau beaucoup plus élevé que cela, donc ce n'est pas non plus une option.
DanP

Je vois. Ensuite, pour répondre à votre question: NOLOCK est un indice de table , et en tant que tel, il s'applique à l'ensemble de lignes auquel est ajouté (table, vue, TVF, etc.). Si plusieurs ensembles de lignes sont joints dans une requête, chacun aura besoin de son propre indice NOLOCK.
Remus Rusanu

2
Mais avez-vous envisagé l'isolement des instantanés? ALTER DATABASE ... SET READ_COMMITTED_SNAPSHOT ON;. Les résultats sont spectaculaires, car toutes les lectures validées normales se transforment en lectures instantanées, sans verrouillage mais cohérentes. Le coût est une tempdbcharge accrue : msdn.microsoft.com/en-us/library/ms175492.aspx
Remus Rusanu
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.