Supposons que j'ai la requête longue durée suivante
UPDATE [Table1]
SET [Col1] = 'some value'
WHERE [Col2] -- some clause which selects thousands of rows
et supposons que la requête suivante est exécutée pendant l'exécution de la requête ci-dessus
SELECT *
FROM [Table1]
La première requête empêche-t-elle l'exécution de la deuxième requête jusqu'à ce que la première requête soit terminée? Dans l'affirmative, la première requête empêche-t-elle la deuxième requête de s'exécuter sur toutes les lignes ou uniquement sur les lignes impliquées dans la clause WHERE?
MODIFIER:
Supposons que la deuxième requête soit
SELECT [Col1], [Col2]
FROM [Table1]
WHERE [Col2] -- some clause whose matching elements overlap those from
-- the clause in the first query and which has additional matching elements
Je vous recommande de lire Comprendre comment SQL Server exécute une requête , il contient une explication du fonctionnement des lectures et des écritures et du fonctionnement du verrouillage.
La vue à 10000 pieds se présente comme suit:
Ce n'est vraiment que la pointe de l'iceberg. Le sujet est vaste. Dans votre exemple, personne ne peut répondre à votre question sur ce qui est réellement verrouillé car cela dépendra de nombreux facteurs. Bien entendu, aucune application ne doit émettre un SELECT * FROM Table1
car il manque une clause WHERE et utilise *
. Ce sont de mauvaises pratiques car, entre autres, elles conduiront exactement à verrouiller les conflits.
Si vous rencontrez des verrous en lecture et en écriture, vous devez examiner la version des lignes et l'isolement des instantanés. Lire Comprendre les niveaux d'isolement basés sur le contrôle de version des lignes .
Edit: Comme le souligne @ MaxVernon , ce qui suit n'est en aucun cas une suggestion d'utiliser NOLOCK , et je devrais très bien viennent de mentionner la définition du niveau de transaction sur READ UNCOMMITED
et laissez la connotation négative se tenir là que de faire monter NOLOCK
en premier lieu. Donc, comme initialement affiché:
La réponse simple et rapide est "Oui, la première requête bloquera la deuxième requête à moins qu'un indice spécifique ne soit spécifié ( NOLOCK , parfois appelé" lecture incorrecte " ) ou le niveau d'isolement des transactions de la deuxième requête est défini sur READ UNCOMMITED
(qui fonctionne de manière identique), non, ce n'est pas le cas. "
En réponse aux détails supplémentaires fournis dans la question impliquant l'inclusion d'une clause WITH
sur le deuxième SELECT
, s'excluant mutuellement ou non, les interactions entre les deux requêtes seront largement les mêmes.
IF NOT EXISTS ( SELECT 1
FROM sys.objects
WHERE name = 'Foo'
AND type = 'U' )
BEGIN
--DROP TABLE dbo.Foo;
CREATE TABLE dbo.Foo
(
Foo_PK BIGINT IDENTITY( 1, 1 ) NOT NULL,
PRIMARY KEY ( Foo_PK ),
Bar BIT,
x BIT,
y BIT,
z BIT
);
CREATE NONCLUSTERED INDEX IX_Foo_x
ON dbo.Foo ( x );
INSERT INTO dbo.Foo ( Bar, x, y, z )
VALUES ( 1, 1, 1, 1 ), ( 0, 0, 0, 0 );
END;
GO
BEGIN TRANSACTION;
UPDATE dbo.Foo
SET y = 0
WHERE x = 1;
-- COMMIT TRANSACTION;
Dans une session distincte, exécutez ce qui suit:
SELECT *
FROM dbo.Foo WITH ( NOLOCK );
GO
SELECT *
FROM dbo.Foo;
Vous pouvez examiner les verrous actuellement détenus en exécutant sp_lock
, de préférence dans une autre session distincte:
EXECUTE dbo.sp_lock;
Vous devriez voir un verrou de type KEY
détenu par le spid effectuant la transaction d'insertion en mode X
(exclusif), à ne pas confondre avec l'autre IX
(Intent-Exclusive ) verrous. La documentation lock indique que si le verrou KEY
est spécifique à la plage, il empêche également d'autres transactions d'insérer ou de mettre à jour les colonnes affectées en modifiant les données qui y sont contenues afin qu'elles puissent tomber. dans cette plage de la requête d'origine. Le verrou lui-même étant exclusif, la première requête empêche l'accès à la ressource de any autre transaction simultanée. En effet, toutes les lignes de la colonne sont verrouillées, qu'elles appartiennent ou non à la plage spécifiée par la première requête.
Le verrou S
détenu par la deuxième session va donc WAIT
jusqu'à ce que le verrou X
soit effacé, empêchant un autre X
(ou U
) que le verrou ne soit pris sur cette ressource à partir d'un autre SPID simultané avant que la deuxième session ne termine son opération de lecture, justifiant l'existence du verrou S
.
Maintenant, une modification pour plus de clarté: à moins que je ne me trompe en ce qui concerne une lecture sale de la brève description des risques mentionnés ici ... Edit 3 : Je viens de réaliser que je ne considère pas l'effet d'un point de contrôle en arrière-plan qui écrit une transaction non encore validée sur le disque, alors oui, mon explication était trompeuse.
Dans la deuxième requête, le premier lot peut (et dans ce cas, renverra) des données non validées. Le deuxième lot, exécuté dans le niveau d'isolation de transaction par défaut de READ COMMITED
ne reviendra qu'après la validation ou la restauration de la première session.
De là, vous pouvez consulter vos plans de requête et les niveaux de verrouillage associés, mais mieux encore, vous pouvez tout lire sur les verrous dans SQL Server ici .