Tại sao UPDLOCK khiến CHỌN bị treo (khóa)?


13

Tôi đã có một lựa chọn trong SQL SERVER khóa toàn bộ bảng.

Đây là tập lệnh thiết lập (đảm bảo bạn không ghi đè lên bất cứ điều gì)

USE [master]
GO

IF EXISTS(SELECT 1 FROM sys.databases d WHERE d.name = 'LockingTestDB')
DROP DATABASE LockingTestDB
GO

CREATE DATABASE LockingTestDB
GO

USE [LockingTestDB]
GO
IF EXISTS(SELECT 1 FROM sys.tables t WHERE t.name = 'LockingTestTable')
  DROP TABLE LockingTestTable
GO

CREATE TABLE LockingTestTable (
  Id int IDENTITY(1, 1),
  Name varchar(100),
  PRIMARY KEY CLUSTERED (Id)
)
GO

INSERT INTO LockingTestTable(Name) VALUES ('1')
INSERT INTO LockingTestTable(Name) VALUES ('2')
GO

Mở một cửa sổ truy vấn mới và chạy giao dịch sau (có chờ trong đó):

USE [LockingTestDB]
GO

BEGIN TRANSACTION
  SELECT * FROM LockingTestTable t WITH (UPDLOCK, ROWLOCK) WHERE t.Name = '1'
  WAITFOR DELAY '00:01:00'

COMMIT TRANSACTION
--ROLLBACK
GO

USE [master]
GO

Và một cái khác sẽ chạy (đảm bảo chúng chạy cùng một lúc):

USE [LockingTestDB]
GO

SELECT * FROM LockingTestTable t WITH (UPDLOCK, ROWLOCK) WHERE t.Name = '2'

USE [master]
GO

Bạn sẽ nhận thấy truy vấn thứ hai sẽ bị chặn bởi truy vấn thứ nhất. Dừng truy vấn đầu tiên và thực hiện ROLLBACK và lần thứ hai sẽ hoàn thành.

Tại sao chuyện này đang xảy ra?

PS: Thêm chỉ mục không được nhóm (có phạm vi bảo hiểm đầy đủ) vào Tên sẽ khắc phục:

USE [LockingTestDB]
GO

CREATE NONCLUSTERED INDEX [IX_Name] ON [dbo].[LockingTestTable] 
(
  [Name] ASC
)
INCLUDE ( [Id]) WITH (STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Một lần nữa tại sao?

Câu trả lời:


19

Như tài liệu trong Books Online , UPDLOCKlấy các khóa cập nhật và giữ chúng đến cuối giao dịch.

Không có chỉ mục để xác định (các) hàng bị khóa, tất cả các hàng được kiểm tra sẽ bị khóa và khóa trên các hàng đủ điều kiện được giữ cho đến khi giao dịch hoàn tất.

Giao dịch đầu tiên giữ khóa cập nhật trên hàng trong đó name = 1. Giao dịch thứ hai bị chặn khi cố gắng lấy khóa cập nhật trên cùng một hàng (để kiểm tra xem name = 2 cho hàng đó).

Với một chỉ mục, SQL Server có thể nhanh chóng định vị và chỉ khóa những hàng đủ điều kiện, do đó không có xung đột.

Bạn nên xem lại mã với một chuyên gia cơ sở dữ liệu đủ điều kiện để xác thực lý do cho gợi ý khóa và để đảm bảo có các chỉ mục thích hợp.

Thông tin liên quan: Sửa đổi dữ liệu trong phần Đọc cách ly Ảnh chụp đã cam kết

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.