คำตอบนี้อาจพิสูจน์ได้ว่าเป็นประโยชน์กับคำถามต้นฉบับ แต่โดยหลักแล้วจะเน้นข้อมูลที่ไม่ถูกต้องในโพสต์อื่น นอกจากนี้ยังเน้นหัวข้อไร้สาระใน BOL
และตามที่ระบุไว้ในเอกสารINSERTมันจะได้รับล็อคพิเศษบนโต๊ะ วิธีเดียวที่เลือกได้กับตารางคือใช้ NOLOCK หรือตั้งค่าระดับการแยกของธุรกรรม
ส่วนที่เชื่อมโยงของสถานะ BOL:
คำสั่ง INSERT จะได้รับการล็อคเอกสิทธิ์ (X) บนโต๊ะที่ปรับเปลี่ยนและเก็บล็อกนั้นไว้จนกว่าธุรกรรมจะเสร็จสมบูรณ์ ด้วยการล็อคแบบเอกสิทธิ์ (X) ไม่มีธุรกรรมอื่นใดสามารถแก้ไขข้อมูลได้ การดำเนินการอ่านสามารถเกิดขึ้นได้เฉพาะกับการใช้คำใบ้ NOLOCK หรืออ่านระดับการแยกที่ปราศจากข้อผูกมัด สำหรับข้อมูลเพิ่มเติมโปรดดูที่ล็อคในโปรแกรมฐานข้อมูล
หมายเหตุ: ตั้งแต่ 2014-8-27 BOL ได้รับการปรับปรุงเพื่อลบข้อความที่ไม่ถูกต้องที่อ้างถึงข้างต้น
โชคดีที่มันไม่ได้เป็นอย่างนั้น หากมีการแทรกลงในตารางอย่างมากและผู้อ่านทั้งหมดจะถูกบล็อกจากตารางทั้งหมดจนกว่าธุรกรรมแทรกจะเสร็จสิ้น นั่นจะทำให้ SQL Server เป็นเซิร์ฟเวอร์ฐานข้อมูลที่มีประสิทธิภาพเช่นเดียวกับ NTFS ไม่มาก.
สามัญสำนึกแสดงให้เห็นว่ามันไม่สามารถจะเป็นอย่างนั้น แต่ขณะที่พอลแรนดัลชี้ให้เห็น " ตัวเองไม่ชอบไว้วางใจไม่มีใคร " หากคุณไม่สามารถเชื่อใจใครได้รวมถึงBOLฉันเดาว่าเราจะต้องพิสูจน์มัน
สร้างฐานข้อมูลและเติมข้อมูลตารางดัมมีหลายแถวโดยสังเกตว่า DatabaseId ส่งคืน
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
ตั้งค่าการติดตาม profiler ที่จะติดตามการล็อก: ที่ได้มาและการล็อก: เหตุการณ์ที่นำออกใช้, การกรองบน DatabaseId จากสคริปต์ก่อนหน้า, การตั้งค่าพา ธ สำหรับไฟล์และแจ้งให้ TraceId ส่งคืน
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
แทรกแถวและหยุดการติดตาม:
USE LockDemo
GO
INSERT MyTable DEFAULT VALUES
GO
EXEC sp_trace_setstatus 3, 0
EXEC sp_trace_setstatus 3, 2
GO
เปิดไฟล์ติดตามและคุณควรพบสิ่งต่อไปนี้:
ลำดับของการล็อคคือ:
- ล็อค Intent-Exclusive บน MyTable
- การล็อก Intent-Exclusive บนหน้า 1: 211
- RangeInsert-NullResource ในรายการดัชนีคลัสเตอร์สำหรับค่าที่ถูกแทรก
- กุญแจล็อคพิเศษ
ล็อคจะถูกปล่อยออกมาในลำดับกลับกัน ไม่มีการล็อคแบบเอกสิทธิ์ที่ได้มาบนโต๊ะ
แต่นี่เป็นเพียงการแทรกแบทช์! นั่นไม่เหมือนกับการวิ่งสองสามหรือสิบขนาน
ใช่แล้ว. SQL Server (และเอ็นจิ้นฐานข้อมูลเชิงสัมพันธ์ใด ๆ ) ไม่มีการคาดการณ์ล่วงหน้าว่าแบทช์ใดที่อาจทำงานอยู่เมื่อประมวลผลคำสั่งและ / หรือแบทช์ดังนั้นลำดับของการได้รับการล็อกจะไม่แตกต่างกัน
ระดับการแยกที่สูงขึ้นเช่น Serializable คืออะไร
สำหรับตัวอย่างนี้โดยเฉพาะจะมีการล็อคตัวเดียวกันทุกประการ อย่าเชื่อฉันลองดูสิ!