" Lock Escalation " adalah cara SQL menangani penguncian untuk update besar. Ketika SQL akan mengubah banyak baris, lebih efisien bagi mesin database untuk mengambil lebih sedikit, kunci yang lebih besar (misalnya seluruh tabel) daripada mengunci banyak hal yang lebih kecil (misalnya kunci baris).
Tetapi ini bisa menjadi masalah ketika Anda memiliki tabel besar, karena mengunci seluruh tabel dapat mengunci kueri lain untuk waktu yang lama. Itulah kompromi: banyak kunci granularitas kecil lebih lambat daripada lebih sedikit (atau satu) kunci berbutir kasar, dan memiliki beberapa kueri yang mengunci bagian berbeda dari tabel menciptakan kemungkinan kebuntuan jika satu proses menunggu proses lainnya.
Ada opsi tingkat tabel LOCK_ESCALATION
, baru di SQL 2008, yang memungkinkan kontrol eskalasi kunci. Defaultnya, "TABLE" memungkinkan kunci untuk meningkat hingga ke tingkat tabel. NONAKTIFKAN mencegah eskalasi lock ke seluruh tabel dalam banyak kasus. AUTO memungkinkan penguncian tabel kecuali jika tabel dipartisi, dalam hal ini penguncian hanya dibuat hingga tingkat partisi. Lihat posting blog ini untuk info lebih lanjut.
Saya menduga bahwa IDE menambahkan pengaturan ini saat membuat ulang tabel karena TABLE adalah default di SQL 2008. Perhatikan bahwa LOCK_ESCALATION tidak didukung di SQL 2005, jadi Anda harus menghapusnya jika mencoba menjalankan skrip pada 2005 contoh. Selain itu, karena TABLE adalah defaultnya, Anda dapat dengan aman menghapus baris tersebut saat menjalankan kembali skrip Anda.
Perhatikan juga bahwa, di SQL 2005 sebelum pengaturan ini ada, semua kunci bisa meningkat ke tingkat tabel-- dengan kata lain, "TABLE" adalah satu-satunya pengaturan di SQL 2005.
CREATE TABLE
karena tabel belum ada sehingga tidak ada yang perlu dikunci.ALTER TABLE
pernyataan terpisah . PertamaALTER TABLE ADD column
, laluGO
, lalu keduaALTER TABLE SET LOCK_ESCALATION=TABLE
, lalu keduaGO
. Jadi,LOCK_ESCALATION
diatur setelah kolom ditambahkan. Apa gunanya mengaturnya setelah fakta? KeduaALTER TABLE
pernyataan ini dibungkus dalam sebuah transaksi, tetapi tetap saja kolom ditambahkan sebelumLOCK_ESCALATION
ditetapkan. Saya pikir saya akan menggali lebih jauh dan menulis jawaban lain.Anda dapat memeriksa apakah Anda perlu menyertakan pernyataan LOCK_ESCALATION dalam skrip Anda dengan membandingkan nilai ini sebelum dan setelah menjalankan bagian utama skrip Anda:
SELECT lock_escalation_desc FROM sys.tables WHERE name='yourtablename'
Dalam kasus saya, mengubah tabel menjadi menjatuhkan atau menambah batasan tampaknya tidak mengubah nilai ini.
sumber
Jawaban oleh Justin Grant menjelaskan apa yang
LOCK_ESCALATION
dilakukan pengaturan secara umum, tetapi melewatkan satu detail penting dan tidak menjelaskan mengapa SSMS menghasilkan kode yang menetapkannya. Terutama, terlihat sangat aneh bahwaLOCK_ESCALATION
disetel sebagai pernyataan terakhir dalam skrip.Saya melakukan beberapa tes dan inilah pemahaman saya tentang apa yang terjadi di sini.
Versi pendek
The
ALTER TABLE
pernyataan yang menambahkan, tetes atau alter kolom implisit mengambil skema memodifikasi (SCH-M) kunci di atas meja, yang tidak ada hubungannya denganLOCK_ESCALATION
pengaturan meja.LOCK_ESCALATION
mempengaruhi mengunci perilaku selama laporan DML (INSERT
,UPDATE
,DELETE
, dll), tidak selama laporan DDL (ALTER
). Kunci SCH-M selalu merupakan kunci dari seluruh objek database, tabel dalam contoh ini.Sepertinya dari sinilah kebingungan itu berasal.
SSMS menambahkan
ALTER TABLE <TableName> SET (LOCK_ESCALATION = ...)
pernyataan tersebut ke skripnya dalam semua kasus, bahkan jika tidak diperlukan. Dalam kasus ketika pernyataan ini diperlukan, itu ditambahkan untuk mempertahankan pengaturan tabel saat ini, bukan untuk mengunci tabel dengan cara tertentu selama perubahan pada skema tabel yang terjadi dalam skrip itu.Dengan kata lain, meja yang terkunci dengan kunci SCH-M pada pertama
ALTER TABLE ALTER COLUMN
pernyataan sementara semua pekerjaan mengubah skema tabel dilakukan.ALTER TABLE SET LOCK_ESCALATION
Pernyataan terakhir tidak mempengaruhinya. Ini mempengaruhi hanya pernyataan DML masa depan (INSERT
,UPDATE
,DELETE
, dll) untuk meja itu.Pada pandangan pertama, ini terlihat seolah-olah
SET LOCK_ESCALATION = TABLE
ada hubungannya dengan fakta bahwa kami mengubah seluruh tabel (kami mengubah skema di sini), tetapi menyesatkan.Versi panjang
Saat mengubah tabel dalam beberapa kasus, SSMS menghasilkan skrip yang membuat ulang seluruh tabel dan dalam beberapa kasus yang lebih sederhana (seperti menambahkan atau menghapus kolom) skrip tidak membuat ulang tabel.
Mari kita ambil tabel contoh ini sebagai contoh:
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
Setiap tabel memiliki
LOCK_ESCALATION
pengaturan, yang diaturTABLE
secara default. Mari kita ubah di sini:ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)
Sekarang, jika saya mencoba mengubah
Col1
tipe di desainer tabel SSMS, SSMS menghasilkan skrip yang membuat ulang seluruh tabel: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
Anda dapat melihat di atas yang ditetapkan
LOCK_ESCALATION
untuk tabel yang baru dibuat. SSMS melakukannya untuk mempertahankan pengaturan tabel saat ini. SSMS membuat baris ini, meskipun nilai setelan saat ini adalah nilai defaultTABLE
. Hanya untuk aman dan eksplisit dan mencegah kemungkinan masalah di masa depan jika di masa depan default ini berubah, saya rasa. Ini masuk akal.Dalam contoh ini sangat diperlukan untuk menghasilkan
SET LOCK_ESCALATION
pernyataan, karena tabel dibuat baru dan pengaturannya harus dipertahankan.Jika saya mencoba membuat perubahan sederhana ke tabel menggunakan desainer tabel SSMS, seperti menambahkan kolom baru, maka SSMS menghasilkan skrip yang tidak membuat ulang tabel:
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
Seperti yang Anda lihat, itu masih menambahkan
ALTER TABLE SET LOCK_ESCALATION
pernyataan, meskipun dalam hal ini tidak diperlukan sama sekali. Yang pertamaALTER TABLE ... ADD
tidak mengubah pengaturan saat ini. Saya kira, pengembang SSMS memutuskan bahwa tidak sepadan dengan upaya untuk mencoba menentukan dalam kasus apaALTER TABLE SET LOCK_ESCALATION
pernyataan ini berlebihan dan selalu menghasilkannya, hanya untuk amannya. Tidak ada salahnya menambahkan pernyataan ini setiap saat.Sekali lagi,
LOCK_ESCALATION
pengaturan seluruh tabel tidak relevan sementara skema tabel berubah melaluiALTER TABLE
pernyataan.LOCK_ESCALATION
pengaturan hanya mempengaruhi perilaku penguncian pernyataan DML, sepertiUPDATE
.Akhirnya, kutipan dari
ALTER TABLE
, tekankan milik saya:sumber