Câu trả lời này có thể hữu ích cho câu hỏi ban đầu nhưng chủ yếu là để giải quyết thông tin không chính xác trong các bài đăng khác. Nó cũng nêu bật một phần vô nghĩa trong BOL.
Và như đã nêu trong tài liệu INSERT , nó sẽ có được một khóa độc quyền trên bàn. Cách duy nhất CHỌN có thể được thực hiện đối với bảng là sử dụng NOLOCK hoặc đặt mức cô lập của giao dịch.
Phần được liên kết của các trạng thái BOL:
Một câu lệnh INSERT luôn có được một khóa (X) độc quyền trên bảng mà nó sửa đổi và giữ khóa đó cho đến khi giao dịch hoàn tất. Với khóa (X) độc quyền, không có giao dịch nào khác có thể sửa đổi dữ liệu; hoạt động đọc chỉ có thể diễn ra với việc sử dụng gợi ý NOLOCK hoặc đọc mức cô lập không được cam kết. Để biết thêm thông tin, hãy xem Khóa trong Cơ sở dữ liệu .
Lưu ý: Kể từ 2014-8-27 BOL đã được cập nhật để xóa các tuyên bố không chính xác được trích dẫn ở trên.
Rất may đây không phải là trường hợp. Nếu nó được chèn vào một bảng sẽ xảy ra nghiêm trọng và tất cả các độc giả sẽ bị chặn khỏi toàn bộ bảng cho đến khi giao dịch chèn hoàn tất. Điều đó sẽ làm cho SQL Server hiệu quả như một máy chủ cơ sở dữ liệu như NTFS. Không hẳn.
Tâm lý chung cho thấy điều đó không thể như vậy nhưng như Paul Randall chỉ ra rằng: " Hãy tự giúp mình, tin tưởng không ai ". Nếu bạn không thể tin tưởng bất cứ ai, kể cả BOL , tôi đoán chúng ta sẽ phải chứng minh điều đó.
Tạo một cơ sở dữ liệu và điền vào một bảng giả với một loạt các hàng, lưu ý rằng DatabaseId được trả về.
SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;
USE [master]
GO
IF EXISTS (SELECT name FROM sys.databases WHERE name = N'LockDemo')
DROP DATABASE [LockDemo]
GO
DECLARE @DataFilePath NVARCHAR(4000)
SELECT
@DataFilePath = SUBSTRING(physical_name, 1, CHARINDEX(N'master.mdf', LOWER(physical_name)) - 1)
FROM
master.sys.master_files
WHERE
database_id = 1 AND file_id = 1
EXEC ('
CREATE DATABASE [LockDemo] ON PRIMARY
( NAME = N''LockDemo'', FILENAME = N''' + @DataFilePath + N'LockDemo.mdf' + ''', SIZE = 2MB , MAXSIZE = UNLIMITED, FILEGROWTH = 2MB )
LOG ON
( NAME = N''LockDemo_log'', FILENAME = N''' + @DataFilePath + N'LockDemo_log.ldf' + ''', SIZE = 1MB , MAXSIZE = UNLIMITED , FILEGROWTH = 1MB )
')
GO
USE [LockDemo]
GO
SELECT DB_ID() AS DatabaseId
CREATE TABLE [dbo].[MyTable]
(
[id] [int] IDENTITY(1,1) PRIMARY KEY CLUSTERED
, [filler] CHAR(4030) NOT NULL DEFAULT REPLICATE('A', 4030)
)
GO
INSERT MyTable DEFAULT VALUES;
GO 100
Thiết lập theo dõi hồ sơ sẽ theo dõi khóa: thu được và khóa: các sự kiện đã phát hành, lọc trên DatabaseId từ tập lệnh trước đó, đặt đường dẫn cho tệp và lưu ý TraceId được trả về.
declare @rc int
declare @TraceID int
declare @maxfilesize BIGINT
declare @databaseid INT
DECLARE @tracefile NVARCHAR(4000)
set @maxfilesize = 5
SET @tracefile = N'D:\Temp\LockTrace'
SET @databaseid = 9
exec @rc = sp_trace_create @TraceID output, 0, @tracefile, @maxfilesize, NULL
if (@rc != 0) goto error
declare @on bit
set @on = 1
exec sp_trace_setevent @TraceID, 24, 32, @on
exec sp_trace_setevent @TraceID, 24, 1, @on
exec sp_trace_setevent @TraceID, 24, 57, @on
exec sp_trace_setevent @TraceID, 24, 3, @on
exec sp_trace_setevent @TraceID, 24, 51, @on
exec sp_trace_setevent @TraceID, 24, 12, @on
exec sp_trace_setevent @TraceID, 60, 32, @on
exec sp_trace_setevent @TraceID, 60, 57, @on
exec sp_trace_setevent @TraceID, 60, 3, @on
exec sp_trace_setevent @TraceID, 60, 51, @on
exec sp_trace_setevent @TraceID, 60, 12, @on
exec sp_trace_setevent @TraceID, 23, 32, @on
exec sp_trace_setevent @TraceID, 23, 1, @on
exec sp_trace_setevent @TraceID, 23, 57, @on
exec sp_trace_setevent @TraceID, 23, 3, @on
exec sp_trace_setevent @TraceID, 23, 51, @on
exec sp_trace_setevent @TraceID, 23, 12, @on
-- DatabaseId filter
exec sp_trace_setfilter @TraceID, 3, 0, 0, @databaseid
-- Set the trace status to start
exec sp_trace_setstatus @TraceID, 1
-- display trace id for future references
select TraceID=@TraceID
goto finish
error:
select ErrorCode=@rc
finish:
go
Chèn một hàng và dừng theo dõi:
USE LockDemo
GO
INSERT MyTable DEFAULT VALUES
GO
EXEC sp_trace_setstatus 3, 0
EXEC sp_trace_setstatus 3, 2
GO
Mở tệp theo dõi và bạn sẽ tìm thấy như sau:
Trình tự các khóa được thực hiện là:
- Khóa Intent-Exclusive trên MyTable
- Khóa Intent-Exclusive trên trang 1: 211
- RangeInsert-NullResource trên mục nhập chỉ mục được nhóm cho giá trị được chèn
- Khóa độc quyền trên chìa khóa
Các khóa sau đó được phát hành theo thứ tự ngược lại. Không có lúc nào có một khóa độc quyền được mua trên bàn.
Nhưng đây chỉ là một đợt chèn! Điều đó không giống như hai, ba hoặc hàng chục chạy song song.
Vâng, đúng vậy. SQL Server (và được cho là bất kỳ công cụ cơ sở dữ liệu quan hệ nào) không có tầm nhìn xa về những lô khác có thể đang chạy khi nó xử lý một câu lệnh và / hoặc lô, do đó trình tự thu thập khóa không thay đổi.
Điều gì về mức độ cô lập cao hơn, ví dụ như serializable?
Đối với ví dụ cụ thể này chính xác các khóa tương tự được thực hiện. Đừng tin tôi, hãy thử nó!