La réponse de Justin Grant explique ce que fait le LOCK_ESCALATION
paramè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 TABLE
instruction 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_ESCALATION
réglage d'une table.LOCK_ESCALATION
affecte 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 COLUMN
instruction pendant que tout le travail de modification du schéma de table est effectué. La dernière ALTER TABLE SET LOCK_ESCALATION
dé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_ESCALATION
paramètre, qui est défini TABLE
par défaut. Changeons-le ici:
ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)
Maintenant, si j'essaie de changer le Col1
type 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_ESCALATION
pour 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 TABLE
valeur 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_ESCALATION
instruction, 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_ESCALATION
instruction, même si dans ce cas, ce n'est pas du tout nécessaire. Le premier ALTER TABLE ... ADD
ne 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_ESCALATION
paramètre à l' échelle de la table n'est pas pertinent alors que le schéma de la table change via l' ALTER TABLE
instruction. LOCK_ESCALATION
paramè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.