エスカレーションのロック-ここで何が起こっていますか?


138

SQL Server 2008でテーブルを変更(列を削除)しているときに、[変更スクリプトの生成]ボタンをクリックしたところ、生成された変更スクリプトによって列が削除され、 "go"と表示された後、設定されているように見える追加のALTER TABLEステートメントを実行しました。テーブルのロックエスカレーションを「TABLE」に。例:

ALTER TABLE dbo.Contract SET (LOCK_ESCALATION = TABLE)

また、これは変更スクリプトが実行する最後の処理であることにも注意してください。ここで何をしているのですか、なぜLOCK_ESCALATIONをTABLEに設定しているのですか?

回答:


165

ロックエスカレーション」は、SQLが大規模な更新のロックを処理する方法です。SQLが多くの行を変更する場合、データベースエンジンが多くの小さなもの(例:行ロック)をロックするよりも、少ない大きなロック(例:テーブル全体)を取るほうが効率的です。

ただし、テーブル全体がロックされると、他のクエリが長時間ロックアウトされる可能性があるため、巨大なテーブルがある場合、これは問題になる可能性があります。それはトレードオフです。多くの小さな粒度のロックは、少数(または1つ)の粗粒度のロックよりも遅く、テーブルの異なる部分をロックする複数のクエリがあると、あるプロセスが別のプロセスを待機している場合にデッドロックが発生する可能性があります。

LOCK_ESCALATIONSQL 2008の新しいテーブルレベルのオプションがあり、ロックのエスカレーションを制御できます。デフォルトの「TABLE」では、ロックによってテーブルレベルまでエスカレートできます。DISABLEは、ほとんどの場合、テーブル全体へのロックのエスカレーションを防ぎます。AUTOは、テーブルがパーティション化されている場合を除いて、テーブルロックを許可します。この場合、ロックはパーティションレベルでのみ行われます。詳細については、このブログ投稿を参照してください。

TABLEがSQL 2008のデフォルトであるため、テーブルを再作成するときにIDEがこの設定を追加するのではないかと思います。SQL2005ではLOCK_ESCALATIONがサポートされていないため、スクリプトでスクリプトを実行する場合は、この設定を取り除く必要があります。 2005年インスタンス。また、TABLEがデフォルトであるため、スクリプトを再実行するときにその行を安全に削除できます。

また、この設定が存在する前のSQL 2005では、すべてのロックがテーブルレベルに昇格する可能性がありました。つまり、SQL 2005では「TABLE」のみが設定されていました。



6
@dma_k- CREATE TABLEテーブルがまだ存在せず、ロックするものがないため、このオプションは関係ありません。
ジャスティングラント

1
しかし、SSMSでテーブルを設計するときに、変更スクリプトの最初のALTER TABLE ステートメントの後に LOCK_ESCALATIONステートメントがあるのはなぜですか?確かにその時までには仕事はもう終わりました。テーブルの構造を変更する前にすべきではありませんか?
リバースエンジニア

2
@DaveBoltman-SETは、ALTER TABLEステートメントの一部です。これは別のステートメントではありません。docs.microsoft.com/en-us/sql/t-sql/statements/…を
Justin Grant

2
JustinGrant、それでも、@ DaveBoltmanからの質問は立っています。たとえば、新しい列を追加するためにSSMSが生成するスクリプトには、2つの別々のALTER TABLEステートメントがあります。最初にALTER TABLE ADD column、次にGO、次に2番目ALTER TABLE SET LOCK_ESCALATION=TABLE、次に2番目GO。したがって、LOCK_ESCALATION列が追加された後に設定されます。事後に設定する意味は?これらの2つのALTER TABLEステートメントはトランザクションでラップされていますが、列LOCK_ESCALATIONが設定される前に追加されます。もう少し掘り下げて、別の答えを書こうと思います。
ウラジミールバラノフ2018

11

スクリプトの主要部分の実行前と実行後にこの値を比較することにより、スクリプトにLOCK_ESCALATIONステートメントを含める必要があるかどうかを確認できます。

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

私の場合、テーブルを変更して制約を削除または追加しても、この値は変更されないようです。


11

Justin Grantの答えLOCK_ESCALATIONは、一般的にどのような設定が行われるかを説明していますが、1つの重要な詳細が欠落しており、SSMSがそれを設定するコードを生成する理由は説明されていません。特に、LOCK_ESCALATIONがスクリプトの最後のステートメントとして設定されているのは非常に奇妙に見えます。

私はいくつかのテストを行いましたが、ここで何が起こっているのかを理解しています。

短縮版

ALTER TABLE追加の文、ドロップまたは変更の列は、暗黙的とは何の関係もありません、テーブル上のスキーマ変更(SCH-M)ロック、かかるLOCK_ESCALATIONテーブルの設定を。LOCK_ESCALATIONDMLステートメント(時の動作をロックする影響INSERTUPDATEDELETE(など)ではないDDLステートメントの間ALTER)。SCH-Mロックは、常にデータベースオブジェクト全体(この例ではテーブル)のロックです。

これはおそらく混乱の原因です。

SSMSは、ALTER TABLE <TableName> SET (LOCK_ESCALATION = ...)必要がない場合でも、すべてのケースでスクリプトにステートメントを追加します。このステートメントが必要な場合は、テーブルの現在の設定を保持するために追加されます。そのスクリプトで発生するテーブルスキーマの変更中に特定の方法でテーブルをロックすることはありません

言い換えれば、テーブルがされた最初のSCH-MロックでロックされたALTER TABLE ALTER COLUMNテーブルのスキーマを変更し、すべての作業が行われている間声明。最後のALTER TABLE SET LOCK_ESCALATIONステートメントはそれに影響を与えません。それだけで、将来のDML文(影響INSERTUPDATEDELETEそのテーブルの、など)。

一見する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)

Col1SSMSテーブルデザイナでタイプを変更しようとすると、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 TABLELOCK_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ステートメントと同じように注意して実行する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.