Câu trả lời của Justin Grant giải thích những gì LOCK_ESCALATION
thiết lập nói chung, nhưng bỏ lỡ một chi tiết quan trọng và nó không giải thích tại sao SSMS tạo mã đặt nó. Đặc biệt, có vẻ rất lạ khi nó LOCK_ESCALATION
được đặt làm tuyên bố cuối cùng trong kịch bản.
Tôi đã làm một vài bài kiểm tra và đây là sự hiểu biết của tôi về những gì đang xảy ra ở đây.
Phiên bản ngắn
Câu ALTER TABLE
lệnh thêm, giảm hoặc thay đổi một cột hoàn toàn lấy khóa sửa đổi lược đồ (SCH-M) trên bảng, điều này không liên quan gì đến việc LOCK_ESCALATION
thiết lập bảng. LOCK_ESCALATION
ảnh hưởng đến hành vi khóa trong các báo cáo DML ( INSERT
, UPDATE
, DELETE
, vv), không trong câu lệnh DDL ( ALTER
). Khóa SCH-M luôn là khóa của toàn bộ đối tượng cơ sở dữ liệu, bảng trong ví dụ này.
Đây có thể là nơi sự nhầm lẫn đến từ.
SSMS thêm ALTER TABLE <TableName> SET (LOCK_ESCALATION = ...)
câu lệnh vào tập lệnh của nó trong mọi trường hợp, ngay cả khi không cần thiết. Trong trường hợp khi cần câu lệnh này, nó được thêm vào để duy trì cài đặt hiện tại của bảng, không khóa bảng theo một cách cụ thể nào đó trong quá trình thay đổi lược đồ bảng xảy ra trong tập lệnh đó.
Nói cách khác, bảng được khóa bằng khóa SCH-M trên ALTER TABLE ALTER COLUMN
câu lệnh đầu tiên trong khi tất cả công việc thay đổi lược đồ bảng được thực hiện. ALTER TABLE SET LOCK_ESCALATION
Tuyên bố cuối cùng không ảnh hưởng đến nó. Nó ảnh hưởng đến báo cáo DML chỉ trong tương lai ( INSERT
, UPDATE
,DELETE
, vv) cho bảng đó.
Thoạt nhìn trông như thể SET LOCK_ESCALATION = TABLE
có liên quan đến thực tế là chúng ta đang thay đổi toàn bộ bảng (chúng ta đang thay đổi lược đồ của nó ở đây), nhưng nó gây hiểu nhầm.
Phiên bản dài
Khi thay đổi bảng trong một số trường hợp, SSMS tạo ra một tập lệnh tạo lại toàn bộ bảng và trong một số trường hợp đơn giản hơn (như thêm hoặc thả một cột), tập lệnh không tạo lại bảng.
Hãy lấy bảng mẫu này làm ví dụ:
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
Mỗi bảng có một LOCK_ESCALATION
cài đặt, được đặt thành TABLE
mặc định. Hãy thay đổi nó ở đây:
ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)
Bây giờ, nếu tôi cố gắng thay đổi Col1
loại trong trình thiết kế bảng SSMS, SSMS sẽ tạo một tập lệnh tạo lại toàn bộ bảng:
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
Bạn có thể thấy ở trên nó đặt LOCK_ESCALATION
cho bảng vừa tạo. SSMS thực hiện nó để duy trì cài đặt hiện tại của bảng. SSMS tạo dòng này, ngay cả khi giá trị hiện tại của cài đặt là TABLE
giá trị mặc định . Để đảm bảo an toàn và rõ ràng và ngăn ngừa các vấn đề có thể xảy ra trong tương lai nếu trong tương lai, sự thay đổi mặc định này, tôi đoán vậy. Điều này thật ý nghĩa.
Trong ví dụ này, thực sự cần thiết để tạo SET LOCK_ESCALATION
câu lệnh, bởi vì bảng được tạo trước đó và cài đặt của nó phải được giữ nguyên.
Nếu tôi cố gắng thực hiện một thay đổi đơn giản cho bảng bằng trình thiết kế bảng SSMS, chẳng hạn như thêm một cột mới, thì SSMS sẽ tạo một tập lệnh không tạo lại bảng:
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
Như bạn có thể thấy, nó vẫn thêm ALTER TABLE SET LOCK_ESCALATION
tuyên bố, mặc dù trong trường hợp này nó không cần thiết chút nào. Cái đầu tiên ALTER TABLE ... ADD
không thay đổi cài đặt hiện tại. Tôi đoán, các nhà phát triển SSMS đã quyết định rằng không đáng nỗ lực để cố gắng xác định trong trường hợp nào ALTER TABLE SET LOCK_ESCALATION
tuyên bố này là dư thừa và tạo ra nó luôn luôn, chỉ để an toàn. Không có hại trong việc thêm tuyên bố này mỗi lần.
Một lần nữa, LOCK_ESCALATION
cài đặt toàn bảng không liên quan trong khi lược đồ bảng thay đổi thông qua ALTER TABLE
câu lệnh. LOCK_ESCALATION
cài đặt chỉ ảnh hưởng đến hành vi khóa của các câu lệnh DML, như UPDATE
.
Cuối cùng, một trích dẫn từ ALTER TABLE
, nhấn mạnh của tôi:
Những thay đổi được chỉ định trong ALTER TABLE được triển khai ngay lập tức. Nếu các thay đổi yêu cầu sửa đổi các hàng trong bảng, ALTER TABLE cập nhật các hàng. ALTER TABLE có được khóa sửa đổi lược đồ (SCH-M) trên bảng để đảm bảo rằng không có kết nối nào khác tham chiếu ngay cả siêu dữ liệu cho bảng trong khi thay đổi, ngoại trừ các hoạt động chỉ mục trực tuyến yêu cầu khóa SCH-M rất ngắn ở cuối. Trong thao tác ALTER TABLE vĩ đại SWITCH, khóa được lấy trên cả bảng nguồn và bảng đích. Các sửa đổi được thực hiện cho bảng được ghi lại và có thể phục hồi hoàn toàn. Các thay đổi ảnh hưởng đến tất cả các hàng trong các bảng rất lớn, chẳng hạn như bỏ một cột hoặc, trên một số phiên bản của SQL Server, việc thêm cột KHÔNG NULL với giá trị mặc định, có thể mất nhiều thời gian để hoàn thành và tạo nhiều bản ghi nhật ký. Các câu lệnh ALTER TABLE này phải được thực thi với cùng một cách chăm sóc như bất kỳ câu lệnh INSERT, UPDATE hoặc DELETE nào ảnh hưởng đến nhiều hàng.