Justin Grantの答えLOCK_ESCALATION
は、一般的にどのような設定が行われるかを説明していますが、1つの重要な詳細が欠落しており、SSMSがそれを設定するコードを生成する理由は説明されていません。特に、LOCK_ESCALATION
がスクリプトの最後のステートメントとして設定されているのは非常に奇妙に見えます。
私はいくつかのテストを行いましたが、ここで何が起こっているのかを理解しています。
短縮版
ALTER TABLE
追加の文、ドロップまたは変更の列は、暗黙的とは何の関係もありません、テーブル上のスキーマ変更(SCH-M)ロック、かかるLOCK_ESCALATION
テーブルの設定を。LOCK_ESCALATION
DMLステートメント(時の動作をロックする影響INSERT
、UPDATE
、DELETE
(など)ではないDDLステートメントの間ALTER
)。SCH-Mロックは、常にデータベースオブジェクト全体(この例ではテーブル)のロックです。
これはおそらく混乱の原因です。
SSMSは、ALTER TABLE <TableName> SET (LOCK_ESCALATION = ...)
必要がない場合でも、すべてのケースでスクリプトにステートメントを追加します。このステートメントが必要な場合は、テーブルの現在の設定を保持するために追加されます。そのスクリプトで発生するテーブルスキーマの変更中に特定の方法でテーブルをロックすることはありません。
言い換えれば、テーブルがされた最初のSCH-MロックでロックされたALTER TABLE ALTER COLUMN
テーブルのスキーマを変更し、すべての作業が行われている間声明。最後のALTER TABLE SET LOCK_ESCALATION
ステートメントはそれに影響を与えません。それだけで、将来のDML文(影響INSERT
、UPDATE
、DELETE
そのテーブルの、など)。
一見するSET LOCK_ESCALATION = TABLE
と、テーブル全体を変更している(ここではスキーマを変更している)ことに何らかの関係があるように見えますが、誤解を招く可能性があります。
ロングバージョン
場合によってはテーブルを変更すると、SSMSはテーブル全体を再作成するスクリプトを生成し、より単純なケース(列の追加や削除など)では、スクリプトはテーブルを再作成しません。
例として、このサンプルテーブルを見てみましょう。
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
各テーブルには、デフォルトでLOCK_ESCALATION
設定さTABLE
れている設定があります。ここで変更しましょう:
ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)
Col1
SSMSテーブルデザイナでタイプを変更しようとすると、SSMSはテーブル全体を再作成するスクリプトを生成します。
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
上記でLOCK_ESCALATION
、新しく作成されたテーブルに設定されていることがわかります。SSMSは、テーブルの現在の設定を保存するためにそれを行います。SSMSは、設定の現在の値がデフォルトTABLE
値であっても、この行を生成します。安全で明確であり、将来このデフォルトが変更された場合に起こりうる問題を防ぐために、私は推測します。意味あり。
この例ではSET LOCK_ESCALATION
、テーブルを新しく作成し、その設定を保持する必要があるため、ステートメントを生成する必要があります。
新しい列の追加など、SSMSテーブルデザイナを使用してテーブルに簡単な変更を加えようとすると、SSMSはテーブルを再作成しないスクリプトを生成します。
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
ご覧のとおりALTER TABLE SET LOCK_ESCALATION
、この場合はまったく必要ありませんが、ステートメントが追加されています。1つ目ALTER TABLE ... ADD
は現在の設定を変更しません。おそらく、SSMSの開発者たちは、安全のために、このALTER TABLE SET LOCK_ESCALATION
ステートメントがどのような場合に冗長であり、常に生成するかを決定する努力をする価値はないと判断しました。このステートメントを毎回追加しても害はありません。
この場合も、ステートメントLOCK_ESCALATION
を使用してテーブルスキーマを変更している間は、テーブル全体の設定は関係ありませんALTER TABLE
。LOCK_ESCALATION
設定は、などのDMLステートメントのロック動作にのみ影響しますUPDATE
。
最後に、からの引用はALTER TABLE
、私のものを強調しています:
ALTER TABLEで指定された変更はすぐに実装されます。変更によってテーブル内の行の変更が必要な場合、ALTER TABLEは行を更新します。ALTER TABLEは、テーブルのスキーマ変更(SCH-M)ロックを取得して、変更中に他の接続がテーブルのメタデータも参照しないようにします、最後に非常に短いSCH-Mロックを必要とするオンラインインデックス操作を除きます。ALTER TABLE…SWITCH操作では、ロックはソーステーブルとターゲットテーブルの両方で取得されます。テーブルに加えられた変更はログに記録され、完全に回復可能です。列の削除や、SQL Serverの一部のエディションでは、デフォルト値でNOT NULL列を追加するなど、非常に大きなテーブルのすべての行に影響を与える変更は、完了して多くのログレコードを生成するのに長い時間がかかる場合があります。これらのALTER TABLEステートメントは、多くの行に影響するINSERT、UPDATE、またはDELETEステートメントと同じように注意して実行する必要があります。