Escalade de verrouillage - Que se passe-t-il ici?

138

Lors de la modification d'une table (suppression d'une colonne) dans SQL Server 2008, j'ai cliqué sur le bouton Générer un script de modification et j'ai remarqué que le script de modification qu'il a généré supprime la colonne, dit «go», puis exécute une instruction ALTER TABLE supplémentaire qui semble définir l'escalade du verrou de la table en "TABLE". Exemple:

ALTER TABLE dbo.Contract SET (LOCK_ESCALATION = TABLE)

Je dois également noter que c'est la dernière chose que fait le script de changement. Que fait-il ici et pourquoi définit-il LOCK_ESCALATION sur TABLE?

James Alexander
la source

Réponses:

165

" Lock Escalation " est la façon dont SQL gère le verrouillage pour les mises à jour importantes. Lorsque SQL va changer beaucoup de lignes, il est plus efficace pour le moteur de base de données de prendre moins de verrous plus grands (par exemple, une table entière) au lieu de verrouiller beaucoup de petits éléments (par exemple, des verrous de lignes).

Mais cela peut être problématique lorsque vous avez une table énorme, car le fait de verrouiller la table entière peut verrouiller d'autres requêtes pendant une longue période. C'est le compromis: de nombreux verrous de petite granularité sont plus lents que moins (ou un) verrous à gros grain, et le fait d'avoir plusieurs requêtes verrouillant différentes parties d'une table crée la possibilité d'un blocage si un processus en attend un autre.

Il existe une option au niveau de la table,, LOCK_ESCALATIONnouvelle dans SQL 2008, qui permet de contrôler l'escalade des verrous. La valeur par défaut, «TABLE», permet aux verrous de remonter jusqu'au niveau de la table. DISABLE empêche l'escalade des verrous vers la table entière dans la plupart des cas. AUTO autorise les verrous de table sauf si la table est partitionnée, auquel cas les verrous ne sont constitués qu'au niveau de la partition. Voir ce billet de blog pour plus d'informations.

Je soupçonne que l'EDI ajoute ce paramètre lors de la recréation d'une table car TABLE est la valeur par défaut dans SQL 2008. Notez que LOCK_ESCALATION n'est pas pris en charge dans SQL 2005, vous devrez donc le supprimer si vous essayez d'exécuter le script sur un Instance de 2005. De plus, puisque TABLE est la valeur par défaut, vous pouvez supprimer cette ligne en toute sécurité lors de la réexécution de votre script.

Notez également que, dans SQL 2005 avant que ce paramètre soit présent, tous les verrous pouvaient escalader au niveau de la table - en d'autres termes, "TABLE" était le seul paramètre sur SQL 2005.

Justin Grant
la source
1
Article dupliqué
Jonathan Kehayias
6
@dma_k - Cette option n'est pas pertinente CREATE TABLEcar la table n'existe pas encore donc il n'y a rien à verrouiller.
Justin Grant
1
Mais pourquoi l'instruction LOCK_ESCALATION est-elle après l' instruction ALTER TABLE initiale dans le script de modification lors de la conception d'une table dans SSMS? À ce moment-là, le travail est sûrement déjà fait. Ne devrait-il pas être avant de changer la structure de la table?
Ingénieur inversé
2
@DaveBoltman - le SET fait partie de l'instruction ALTER TABLE. Ce n'est pas une déclaration distincte. Voir docs.microsoft.com/en-us/sql/t-sql/statements/…
Justin Grant
2
JustinGrant, toujours, la question de @DaveBoltman se tient. Le script que SSMS génère pour, par exemple, ajouter une nouvelle colonne a deux ALTER TABLEinstructions distinctes . D'abord ALTER TABLE ADD column, puis GO, puis ensuite , puis ALTER TABLE SET LOCK_ESCALATION=TABLEensuite GO. Donc, LOCK_ESCALATIONest défini après l'ajout de la colonne. Quel est l'intérêt de le régler après coup? Ces deux ALTER TABLEinstructions sont encapsulées dans une transaction, mais la colonne est toujours ajoutée avant la LOCK_ESCALATIONdéfinition de. Je pense que je vais creuser un peu plus et écrire une autre réponse.
Vladimir Baranov
11

Vous pouvez vérifier si vous devez inclure l'instruction LOCK_ESCALATION dans votre script en comparant cette valeur avant et après l'exécution de la partie principale de votre script:

SELECT lock_escalation_desc FROM sys.tables WHERE name='yourtablename'

Dans mon cas, modifier la table pour supprimer ou ajouter une contrainte ne semble pas modifier cette valeur.

Bogdan Verbenets
la source
11

La réponse de Justin Grant explique ce que fait le LOCK_ESCALATIONparamètre en général, mais manque un détail important et n'explique pas pourquoi SSMS génère le code qui le définit. Surtout, il semble très étrange que leLOCK_ESCALATION soit défini comme dernière instruction dans le script.

J'ai fait quelques tests et voici ma compréhension de ce qui se passe ici.

Version courte

L' ALTER TABLEinstruction qui ajoute, supprime ou modifie une colonne prend implicitement un verrou de modification de schéma (SCH-M) sur la table, ce qui n'a rien à voir avec le LOCK_ESCALATIONréglage d'une table.LOCK_ESCALATIONaffecte le comportement de verrouillage dans les déclarations DML ( INSERT, UPDATE, DELETE, etc.), et non pas dans les instructions DDL ( ALTER). Le verrou SCH-M est toujours un verrou de tout l'objet de base de données, tableau dans cet exemple.

C'est probablement de là que vient la confusion.

SSMS ajoute l' ALTER TABLE <TableName> SET (LOCK_ESCALATION = ...)instruction à son script dans tous les cas, même lorsqu'elle n'est pas nécessaire. Dans les cas où cette instruction est nécessaire, elle est ajoutée pour conserver le paramètre actuel de la table, pas pour verrouiller la table d'une manière spécifique lors de la modification du schéma de table qui se produit dans ce script.

En d'autres termes, la table est verrouillée avec le verrou SCH-M sur la première ALTER TABLE ALTER COLUMNinstruction pendant que tout le travail de modification du schéma de table est effectué. La dernière ALTER TABLE SET LOCK_ESCALATIONdéclaration ne l'affecte pas. Cela n'affecte que les futures instructions DML (INSERT , UPDATE,DELETE , etc.) pour cette table.

À première vue, il semble que SET LOCK_ESCALATION = TABLE quelque chose à voir avec le fait que nous changeons toute la table (nous modifions son schéma ici), mais c'est trompeur.

Version longue

Lors de la modification de la table dans certains cas, SSMS génère un script qui recrée la table entière et dans certains cas plus simples (comme l'ajout ou la suppression d'une colonne), le script ne recrée pas la table.

Prenons cet exemple de tableau comme exemple:

CREATE TABLE [dbo].[Test](
    [ID] [int] NOT NULL,
    [Col1] [nvarchar](50) NOT NULL,
    [Col2] [int] NOT NULL,
 CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

Chaque table a un LOCK_ESCALATIONparamètre, qui est défini TABLEpar défaut. Changeons-le ici:

ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)

Maintenant, si j'essaie de changer le Col1type dans le concepteur de table SSMS, SSMS génère un script qui recrée la table entière:

BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_Test
    (
    ID int NOT NULL,
    Col1 nvarchar(10) NOT NULL,
    Col2 int NOT NULL
    )  ON [PRIMARY]
GO
ALTER TABLE dbo.Tmp_Test SET (LOCK_ESCALATION = DISABLE)
GO
IF EXISTS(SELECT * FROM dbo.Test)
     EXEC('INSERT INTO dbo.Tmp_Test (ID, Col1, Col2)
        SELECT ID, CONVERT(nvarchar(10), Col1), Col2 FROM dbo.Test WITH (HOLDLOCK TABLOCKX)')
GO
DROP TABLE dbo.Test
GO
EXECUTE sp_rename N'dbo.Tmp_Test', N'Test', 'OBJECT' 
GO
ALTER TABLE dbo.Test ADD CONSTRAINT
    PK_Test PRIMARY KEY CLUSTERED 
    (
    ID
    ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

GO
COMMIT

Vous pouvez voir ci-dessus qu'il définit LOCK_ESCALATIONpour la table nouvellement créée. SSMS le fait pour conserver le paramètre actuel de la table. SSMS génère cette ligne, même si la valeur actuelle du paramètre est la TABLEvaleur par défaut . Juste pour être sûr et explicite et éviter d'éventuels problèmes futurs si, à l'avenir, cette valeur par défaut change, je suppose. C'est logique.

Dans cet exemple, il est vraiment nécessaire de générer l' SET LOCK_ESCALATIONinstruction, car la table est créée à nouveau et son paramètre doit être conservé.

Si j'essaie d'apporter une modification simple à la table à l'aide du concepteur de table SSMS, par exemple en ajoutant une nouvelle colonne, SSMS génère un script qui ne recrée pas la table:

BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE dbo.Test ADD
    NewCol nchar(10) NULL
GO
ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)
GO
COMMIT

Comme vous pouvez le voir, il ajoute toujours l' ALTER TABLE SET LOCK_ESCALATIONinstruction, même si dans ce cas, ce n'est pas du tout nécessaire. Le premier ALTER TABLE ... ADDne modifie pas le paramètre actuel. Je suppose que les développeurs SSMS ont décidé qu'il ne valait pas la peine d'essayer de déterminer dans quels cas celaALTER TABLE SET LOCK_ESCALATION déclaration est redondante et de la générer toujours, juste pour être sûr. Il n'y a aucun mal à ajouter cette déclaration à chaque fois.

Une fois de plus, le LOCK_ESCALATIONparamètre à l' échelle de la table n'est pas pertinent alors que le schéma de la table change via l' ALTER TABLEinstruction. LOCK_ESCALATIONparamètre affecte uniquement le comportement de verrouillage des instructions DML, commeUPDATE .

Enfin, une citation de ALTER TABLE, souligne la mienne:

Les modifications spécifiées dans ALTER TABLE sont implémentées immédiatement. Si les modifications nécessitent des modifications des lignes de la table, ALTER TABLE met à jour les lignes. ALTER TABLE acquiert un verrou de modification de schéma (SCH-M) sur la table pour s'assurer qu'aucune autre connexion ne référence même les métadonnées de la table pendant la modification, sauf les opérations d'index en ligne qui nécessitent un verrou SCH-M très court à la fin. Dans une opération ALTER TABLE… SWITCH, le verrou est acquis sur les tables source et cible. Les modifications apportées à la table sont consignées et entièrement récupérables. Les modifications qui affectent toutes les lignes dans des tables très volumineuses, telles que la suppression d'une colonne ou, dans certaines éditions de SQL Server, l'ajout d'une colonne NOT NULL avec une valeur par défaut, peuvent prendre du temps à se terminer et générer de nombreux enregistrements de journal. Ces instructions ALTER TABLE doivent être exécutées avec le même soin que toute instruction INSERT, UPDATE ou DELETE qui affecte de nombreuses lignes.

Vladimir Baranov
la source